Compare commits

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

* chore: require more typing

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

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

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

---------

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

* fix: also keep UV_PYTHON out

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

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

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

* fix: revert env order change

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

* Update windows.py

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

---------

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

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


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

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

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

* Remove more template expansion

* Make a string quoting that's compatible with pwsh

* Apply suggestions from code review

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

---------

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

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

* chore: add an extra check

* Apply suggestions from code review

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

* Pin pre-commit hooks too

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

* Print build identifier list in preamble before build loop

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

---------

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

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

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

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

See #2770 for the impetus.

* Lie about a tag to see what happens

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

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

See #2770

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

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

This reverts commit b44f94d7a5c852b93b16157831b698f9c250628d.

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

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

* Write the correct version strings

* ci: some updates based on main branch

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

* ci: move to using latest images

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

* chore: fix up style checks

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

* ci: newer azure images too

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

* tests: use new SSL test from main

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

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
2026-03-16 19:24:46 +00:00
Henry Schreiner fd6b413212 tests: use pytest 9+ and modern config (#2777)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2026-03-13 20:44:48 +01:00
Henry Schreiner 4d4daefbd2 fix: give uv the full python path (#2774)
* fix: give uv the full python path

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

* Fix python binary path in Linux build script

I thought the dir was enough. Seems not.

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2026-03-13 11:11:25 -04:00
Clément Robert 42c502093f SEC: add a 7 days cooldown period to dependabot settings (#2766) 2026-03-12 21:53:23 +00:00
Clément Robert bc6f42d805 SEC: disable default gha permissions (#2771) 2026-03-12 01:15:38 +05:30
Clément Robert eaf116e303 SEC: avoid leaking credentials in GHA (#2769) 2026-03-11 19:50:11 +05:30
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
02c132e91e [pre-commit.ci] pre-commit autoupdate (#2764)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.4 → v0.15.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.4...v0.15.5)
- [github.com/codespell-project/codespell: v2.4.1 → v2.4.2](https://github.com/codespell-project/codespell/compare/v2.4.1...v2.4.2)

* Add autoupdate schedule to pre-commit config

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-03-10 18:36:10 -04:00
Matthieu Darbois fd27532d12 fix: call repair-wheel-command in iOS builds (#2761) 2026-03-09 15:56:45 -04:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 1313a80d3a chore(deps): bump docker/setup-qemu-action from 3 to 4 in the actions group (#2763)
chore(deps): bump docker/setup-qemu-action in the actions group

Bumps the actions group with 1 update: [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action).


Updates `docker/setup-qemu-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-09 15:56:18 -04:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 601935bfc3 [Bot] Update dependencies (#2762)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2026-03-09 12:45:50 -04:00
Joe Rickerby 880a211a08 Add missing PR reference to changelog 2026-03-05 09:03:18 +00:00
Joe Rickerby ee02a1537c Bump version: v3.4.0 2026-03-05 09:00:28 +00:00
Henry Schreiner f08ce70d78 chore: match copyright to BSD-2-clause template (#2758)
See #2757.
2026-03-03 09:51:22 +00:00
Gyeongjae Choi 95b4b79b96 Fix incorrect document regarding pyodide auditwheel (#2752)
* Fix incorrect document for pyodide

* Fix incorrect document for pyodide

* Fix test
2026-03-03 16:55:56 +09:00
f046d0a94d Bump to Pyodide v0.29.3 (#2743)
* Bump to Pyodide v0.29.3

* Bump constraints to fix virtualenv release deletion

---------

Co-authored-by: Joe Rickerby <joerick@mac.com>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-03-02 17:00:30 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f5a31ee79d chore(deps): bump the actions group across 1 directory with 4 updates (#2755)
Bumps the actions group with 4 updates in the / directory: [actions/download-artifact](https://github.com/actions/download-artifact), [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [wntrblm/nox](https://github.com/wntrblm/nox).


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

Updates `actions/attest-build-provenance` from 3.2.0 to 4.1.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/96278af6caaf10aea03fd8d33a09a777ca52d62f...a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32)

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

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

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/attest-build-provenance
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: wntrblm/nox
  dependency-version: 2026.02.09
  dependency-type: direct:production
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-02 16:31:23 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 35ec4565f5 [pre-commit.ci] pre-commit autoupdate (#2756)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.2 → v0.15.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.2...v0.15.4)
- [github.com/python-jsonschema/check-jsonschema: 0.36.2 → 0.37.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.36.2...0.37.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-03-02 16:31:08 -05:00
cibuildwheel-bot[bot]cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>Joe Rickerby
51fed90270 [Bot] Update dependencies (#2734)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2026-03-02 14:15:58 +00:00
Joe Rickerbyjoerickcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>Copilot
b70562f37a Debug GraalPy/uv test failures on Windows (#2741)
* Dont attempt uv frontend tests on gp311.

* docs: note GraalPy 3.11 incompatibility with uv on Windows (#2751)

* Initial plan

* docs: note GraalPy311 incompatibility with uv/build[uv] on Windows

Co-authored-by: joerick <1244307+joerick@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joerick <1244307+joerick@users.noreply.github.com>

* Skip both graalpy with uv for now

* Docs updates

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: joerick <1244307+joerick@users.noreply.github.com>
2026-03-02 11:24:40 +00:00
Joe Rickerby 0a85e29549 Work around CDN rate limiting on Python.org in bin/update_pythons.py (#2753) 2026-03-01 22:51:53 +00:00
Colin Gravill 2d33864baf Pin the actions/setup-python for the externally used action.yml (#2749)
Pin the actions/setup-python to a known release
2026-03-01 22:05:39 +00:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ade95b7be4 [pre-commit.ci] pre-commit autoupdate (#2746)
* [pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/astral-sh/ruff-pre-commit: v0.15.0 → v0.15.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.0...v0.15.2)
- [github.com/python-jsonschema/check-jsonschema: 0.36.1 → 0.36.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.36.1...0.36.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>
2026-03-01 22:02:36 +00:00
Henry Schreiner bb153041f0 fix: support -q for build/uv (#2737) 2026-02-13 20:47:03 -05:00
27fd6ecc3c docs: fix TOML reference links (#2740)
* docs: fix TOML reference links

* Apply suggestions from code review

---------

Co-authored-by: Louis Shawn <louis.shawn@qq.com>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-02-13 21:04:38 +00:00
pre-commit-ci[bot]pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>Henry Schreiner
57e8757899 [pre-commit.ci] pre-commit autoupdate (#2739)
* [pre-commit.ci] pre-commit autoupdate

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

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

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

* Refactor test_command checks to use set syntax

* Apply suggestion from @henryiii

* [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>
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-02-13 11:24:27 -05:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 8879b0f013 chore(deps): bump the actions group with 2 updates (#2738)
Bumps the actions group with 2 updates: [actions/download-artifact](https://github.com/actions/download-artifact) and [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).


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

Updates `actions/attest-build-provenance` from 3.1.0 to 3.2.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/00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8...96278af6caaf10aea03fd8d33a09a777ca52d62f)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/attest-build-provenance
  dependency-version: 3.2.0
  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>
2026-02-09 17:17:39 -05:00
Henry Schreiner 9d4c80f487 docs: update for uv backend (#2736) 2026-02-08 08:35:24 -05:00
Henry Schreiner e0af304d30 fix: support uv on android (#2733) 2026-02-08 08:35:05 -05:00
Joe RickerbyandHenry Schreiner a2f965f62f Add an integration test and debug issues with the meson backend (#2718)
* Add an integration test with the meson backend

* Modify script to allow testing of the GHA action on a PR

* Try adding cython to languages in meson config

* Revert "Try adding cython to languages in meson config"

This reverts commit 50378a1c7e38665492ad0c683b178e4d96928e1e.

* Pass --vsenv to meson on windows

As seen here https://github.com/matplotlib/matplotlib/blob/9957c394bd01deb7a9bd9cb27804f447a52dc522/.github/workflows/cibuildwheel.yml#L114

* Disable win32 builds for the meson test

* Move the windows-specific config into the test project definition

This is so it can be tested with bin/run_example_ci_configs.py

* Add some docs to the FAQ about meson on windows

* Update bin/run_example_ci_configs.py

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

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2026-02-08 10:36:47 +00:00
Henry Schreiner 0d2547bf6f fix: consistently use find_uv for our usage of uv (#2730)
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-02-06 15:50:18 -05:00
Joe Rickerby 1252e6249a test: try reduce flakiness of test_ssl (#2735)
test: replace badssl.com with google.com/generate_204 in SSL test

Switch to a more reliable HTTPS endpoint and add retry logic with
exponential backoff to reduce flaky test failures.
2026-02-06 15:35:20 -05:00
Agriya KhetarpalandJoe Rickerby 42d1caec22 Add a small note about security implications of using cibuildwheel in CI runners (#2711)
* Bump to actions/checkout v6 everywhere

* Add a note about security

* Not persisting credentials is still valuable

* Fix bad indentation

* Improve wording, remove link to PyPA guides

Co-Authored-By: Joe Rickerby <1244307+joerick@users.noreply.github.com>

---------

Co-authored-by: Joe Rickerby <1244307+joerick@users.noreply.github.com>
2026-02-06 18:54:08 +00:00
Henry Schreiner d31248fdbf ci: avoid Intel GraalPy updates (#2732)
* ci: avoid broken GraalPy release

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

* ci: skip GraalPy when no release url available

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

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-02-05 18:01:29 -05:00
Henry Schreiner d7dbf5a358 feat: option to build directly with uv (#2322)
* feat: option to build directly with uv

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

tests: add uv to tests

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

fix: uv doesn't pick special Pythons at the top of the path

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

fix: set uv build constraints too

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

fix: uv doesn't support PyPy 3.8

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

tests: add pyproject.toml for failing test

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

Revert "tests: add pyproject.toml for failing test"

This reverts commit 619bde368a67dfdd8f02dc33a1525c27bc8cbe91.

tests: skip uv output test

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

* tests: uv was in the wrong fixture

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

* fix: from @trim21

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

* tests: improve skipping

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

* fix: some fixes from copilot review

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

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-02-05 12:08:36 -05:00
Joe Rickerby 6088ea2c85 Fix the PATH mangling in action.yml (#2723)
* Fix the PATH mangling in action.yml

Let's put the `uv` on PATH question aside, and fix #2663.

This change ensures that the PATH entries added by Github when you request `shell: bash` don't make it into the pwsh environment. It also keeps the uv binary on PATH if installed via `extras:`.

Would love to get this fixed soon, then we can figure out the right approach regarding `uv` discovery.

* Modify script to allow testing of the GHA action on a PR

Cherry-picked from #2718 and modified so we can test the action.yml file
2026-02-04 09:23:27 +00:00
Andrew Murray be32c5a2ed Update README actions (#2724) 2026-01-31 13:13:32 -05:00
Henry Schreiner e8646fb903 fix: nicer fail message when --only is wrong (#2722)
* fix: nicer fail message when --only is wrong

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

* Update cibuildwheel/__main__.py

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
2026-01-30 16:24:57 +00:00
Matthieu Darbois 6f8121fa47 ci: test action with uv extra (#2712)
* ci: test action with `uv` extra

* fix: uv extra for Android on Linux
2026-01-28 10:16:54 -05:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 7989c25bcd [pre-commit.ci] pre-commit autoupdate (#2720)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.13 → v0.14.14](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.13...v0.14.14)
- [github.com/python-jsonschema/check-jsonschema: 0.36.0 → 0.36.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.36.0...0.36.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-01-27 09:22:47 +00:00
Agriya KhetarpalandGyeongjae Choi 9a15d0851e Bump to Pyodide v0.29.2 (#2719)
* Bump to Pyodide v0.29.2

* Bump the Pyodide constraints too

* Include new auditwheel-emscripten and pyodide-build release

* Bump pyodide-build in test to a newer version

Co-Authored-By: Gyeongjae Choi <def6488@gmail.com>

---------

Co-authored-by: Gyeongjae Choi <def6488@gmail.com>
2026-01-27 09:22:16 +00:00
riri dc4fc9c3fe feat(android): add Rust cross-compilation setup for Android environment (#2650) 2026-01-25 14:13:03 +00:00
Joe Rickerby dcd9f40825 Update Python version range to 3.14 in Github Action (#2716) 2026-01-25 09:14:13 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 90da3e21e2 [pre-commit.ci] pre-commit autoupdate (#2714)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.10 → v0.14.13](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.10...v0.14.13)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-01-19 19:10:45 +00:00
Joe Rickerby f3ba8a83a5 Merge branch '3.3.x' 2026-01-05 20:04:05 +00:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 3cefb9d38c [Bot] Update dependencies (#2709)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2026-01-05 19:59:47 +00:00
Joe Rickerby 298ed2fb2c Bump version: v3.3.1 2026-01-05 19:57:01 +00:00
Joe Rickerbyandmayeut f0ff944318 [3.3.x] Update dependencies (#2708)
* Update deps

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

* update deps

nox -s update_pins

---------

Co-authored-by: mayeut <mayeut@users.noreply.github.com>
2026-01-05 19:51:01 +00:00
Xeonacid aae69a8e1d break: drop unused riscv64 enable option (#2525) 2026-01-04 20:20:29 +01:00
Matthieu Darbois 24bade1d15 break: remove Travis CI support (#2682)
Stop testing on Travis CI.
References to Travis CI are removed from docs.
Travis CI specifics are kept as-is in cibuildwheel itself (mostly logging stuff).
2025-12-29 17:03:03 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> a68c3b27fb [Bot] Update dependencies (#2704)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-12-29 17:01:45 -05:00
Henry Schreiner 99059b7442 chore: use prek in noxfile/ci (#2681) 2025-12-23 18:51:19 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> d0e070e278 [Bot] Update dependencies (#2697)
Update dependencies

Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
2025-12-23 06:44:34 +01:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> bb2f93202e chore(deps): bump actions/attest-build-provenance from 3.0.0 to 3.1.0 in the actions group (#2698)
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 3.0.0 to 3.1.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/977bb373ede98d70efdf65b84cb5f73e068dcc2a...00014ed6ed5efc5b1ab7f7f34a39eb55d41aa4f8)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-23 06:44:14 +01:00
pre-commit-ci[bot]andpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 11597ed249 [pre-commit.ci] pre-commit autoupdate (#2699)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.9 → v0.14.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.9...v0.14.10)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-12-23 06:43:57 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 90422f1824 [Bot] Update dependencies (#2692)
Update dependencies

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

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


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

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

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

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: peter-evans/create-pull-request
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 20:31:18 +01:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 6878a1baeb [Bot] Update dependencies (#2688)
Update dependencies

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

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

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

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

* chore: update for newer mypy

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

---------

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

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

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


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

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 11:28:39 -05:00
cibuildwheel-bot[bot]andcibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com> 6bc6700ab3 [Bot] Update dependencies (#2671)
Update dependencies

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

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

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


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

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

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

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-17 17:51:47 -05:00
140 changed files with 2855 additions and 1848 deletions
+2
View File
@@ -9,3 +9,5 @@ updates:
actions: actions:
patterns: patterns:
- "*" - "*"
cooldown:
default-days: 7
+9 -5
View File
@@ -7,13 +7,17 @@ on:
types: types:
- published - published
permissions: {}
jobs: jobs:
dist: dist:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: hynek/build-and-inspect-python-package@v2 - uses: hynek/build-and-inspect-python-package@efb823f52190ad02594531168b7a2d5790e66516 # v2.14.0
publish: publish:
needs: [dist] needs: [dist]
@@ -27,16 +31,16 @@ jobs:
attestations: write attestations: write
steps: steps:
- uses: actions/download-artifact@v6 - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: Packages name: Packages
path: dist path: dist
- name: Generate artifact attestation for sdist and wheel - name: Generate artifact attestation for sdist and wheel
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with: with:
subject-path: "dist/cibuildwheel-*" subject-path: "dist/cibuildwheel-*"
- uses: pypa/gh-action-pypi-publish@release/v1 - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with: with:
attestations: true attestations: true
+117 -40
View File
@@ -28,6 +28,8 @@ on:
workflow_dispatch: workflow_dispatch:
# allow manual runs on branches without a PR # allow manual runs on branches without a PR
permissions: {}
concurrency: concurrency:
group: test-${{ github.ref }} group: test-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@@ -37,18 +39,44 @@ jobs:
name: Linters (mypy, ruff, etc.) name: Linters (mypy, ruff, etc.)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@v6 with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python id: python
with: with:
python-version: "3.x" python-version: "3.x"
- uses: pre-commit/action@v3.0.1 - uses: j178/prek-action@79f765515bd648eb4d6bb1b17277b7cb22cb6468 # v2.0.0
- name: PyLint checks - name: PyLint checks
run: pipx run --python "${{ steps.python.outputs.python-path }}" nox -s pylint -- --output-format=github run: pipx run --python "${STEPS_PYTHON_OUTPUTS_PYTHON_PATH}" nox -s pylint -- --output-format=github
env:
STEPS_PYTHON_OUTPUTS_PYTHON_PATH: ${{ steps.python.outputs.python-path }}
sample:
name: Generate a sample project
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python
with:
python-version: "3.x"
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies
run: uv sync --no-dev --group test
- name: Generate a sample project
run: uv run --no-sync -m test.test_projects test.test_0_basic.basic_project sample_proj
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: sample_proj
path: sample_proj
test: test:
name: Test on ${{ matrix.os }} (${{ matrix.python_version }}) ${{ matrix.test_select }} name: Test on ${{ matrix.os }} (${{ matrix.python_version }}) ${{ matrix.test_select }}
needs: lint needs: sample
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
@@ -91,28 +119,29 @@ jobs:
test_select: android test_select: android
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@v6 with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python ${{ matrix.python_version }} name: Install Python ${{ matrix.python_version }}
with: with:
python-version: ${{ matrix.python_version }} python-version: ${{ matrix.python_version }}
allow-prereleases: true allow-prereleases: true
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Free up disk space - name: Free up disk space
if: runner.os == 'Linux' if: runner.os == 'Linux' && matrix.test_select != 'android'
run: | run: |
docker system prune -a -f sudo rm -rf $ANDROID_HOME/ndk /opt/hostedtoolcache/CodeQL \
sudo rm -rf $ANDROID_HOME/ndk/{26,28}.* /opt/hostedtoolcache/CodeQL \
/usr/local/lib/node_modules /usr/local/share/chromium \ /usr/local/lib/node_modules /usr/local/share/chromium \
/usr/local/share/powershell /usr/local/share/powershell
df -h df -m
# for oci_container unit tests # for oci_container unit tests
- name: Set up QEMU - name: Set up QEMU
if: runner.os == 'Linux' if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Set up Xcode - name: Set up Xcode
if: ${{ startsWith(matrix.os, 'macos-15') }} if: ${{ startsWith(matrix.os, 'macos-15') }}
@@ -121,15 +150,14 @@ jobs:
sudo xcode-select --switch /Applications/Xcode_16.4.app sudo xcode-select --switch /Applications/Xcode_16.4.app
- name: Install dependencies - name: Install dependencies
run: | run: uv sync --no-dev --group test
uv sync --no-dev --group test
- uses: joerick/pr-labels-action@v1.0.9 - uses: joerick/pr-labels-action@0543b277721e852d821c6738d449f2f4dea03d5f # v1.0.9
- name: Set CIBW_ENABLE - name: Set CIBW_ENABLE
shell: bash shell: bash
run: | run: |
if [[ "${{ github.ref_name }}" == "main" ]]; then if [[ "$GITHUB_REF_NAME" == "main" ]]; then
CIBW_ENABLE=all CIBW_ENABLE=all
else else
# get the default CIBW_ENABLE value from the test module # get the default CIBW_ENABLE value from the test module
@@ -145,9 +173,11 @@ jobs:
fi fi
echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV
- name: Generate a sample project - name: Download a sample project
run: | uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
uv run --no-sync -m test.test_projects test.test_0_basic.basic_project sample_proj with:
name: sample_proj
path: sample_proj
- name: Run a sample build (GitHub Action) - name: Run a sample build (GitHub Action)
uses: ./ uses: ./
@@ -202,7 +232,7 @@ jobs:
run: | run: |
test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1 test $(find wheelhouse_only -name '*.whl' | wc -l) -eq 1
- uses: actions/upload-artifact@v5 - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with: with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: wheelhouse/*.whl path: wheelhouse/*.whl
@@ -210,8 +240,7 @@ jobs:
- name: Test cibuildwheel - name: Test cibuildwheel
env: env:
CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }} CIBW_TEST_RUNTIME: ${{ matrix.test_runtime }}
run: | run: uv run --no-sync bin/run_tests.py --test-select=${{ matrix.test_select || 'native' }} ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }}
uv run --no-sync bin/run_tests.py --test-select=${{ matrix.test_select || 'native' }} ${{ (runner.os == 'Linux' && runner.arch == 'X64') && '--run-podman' || '' }}
emulated-archs: emulated-archs:
name: Get qemu emulated architectures name: Get qemu emulated architectures
@@ -220,11 +249,13 @@ jobs:
outputs: outputs:
archs: ${{ steps.archs.outputs.archs }} archs: ${{ steps.archs.outputs.archs }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@v6 with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Get qemu emulated architectures - name: Get qemu emulated architectures
@@ -243,39 +274,47 @@ jobs:
matrix: matrix:
arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }} arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@v6 with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Run the emulation tests - name: Run the emulation tests
run: uv run --no-sync pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py env:
MATRIX_ARCH: ${{ matrix.arch }}
run: uv run --no-sync pytest --run-emulation "$MATRIX_ARCH" test/test_emulation.py
test-pyodide: test-pyodide:
name: Test pyodide name: Test pyodide
needs: lint needs: sample
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@v6 with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python 3.12 name: Install Python 3.12
with: with:
python-version: '3.12' python-version: '3.12'
- uses: astral-sh/setup-uv@v7 - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
- name: Generate a sample project - name: Download a sample project
run: | uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
uv run --no-sync -m test.test_projects test.test_0_basic.basic_project sample_proj with:
name: sample_proj
path: sample_proj
- name: Run a sample build (GitHub Action) - name: Run a sample build (GitHub Action)
uses: ./ uses: ./
@@ -286,7 +325,45 @@ jobs:
CIBW_PLATFORM: pyodide CIBW_PLATFORM: pyodide
- name: Run tests with 'CIBW_PLATFORM' set to 'pyodide' - name: Run tests with 'CIBW_PLATFORM' set to 'pyodide'
run: | run: uv run --no-sync ./bin/run_tests.py
uv run --no-sync ./bin/run_tests.py
env: env:
CIBW_PLATFORM: pyodide CIBW_PLATFORM: pyodide
test-uv-extras:
name: Test uv extra on ${{ matrix.os }} ${{ matrix.test_select }}
needs: sample
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
test_select: android
- os: windows-latest
- os: windows-11-arm
- os: macos-15-intel
- os: macos-15
- os: macos-15-intel
test_select: android
- os: macos-15
test_select: android
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download a sample project
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sample_proj
path: sample_proj
- name: Run a sample build (GitHub Action)
uses: ./
with:
extras: uv
package-dir: sample_proj
output-dir: wheelhouse
env:
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
CIBW_BUILD: cp314-*
CIBW_BUILD_FRONTEND: 'build[uv]'
CIBW_PLATFORM: ${{ matrix.test_select }}
+11 -4
View File
@@ -14,25 +14,32 @@ on:
schedule: schedule:
- cron: '0 6 * * 1' # "At 06:00 on Monday." - cron: '0 6 * * 1' # "At 06:00 on Monday."
permissions: {}
jobs: jobs:
update-dependencies: update-dependencies:
name: Update dependencies name: Update dependencies
if: github.repository_owner == 'pypa' || github.event_name != 'schedule' if: github.repository_owner == 'pypa' || github.event_name != 'schedule'
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: write
environment: ${{ github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' && 'update-dependencies-workflow' || '' }}
steps: steps:
# we use this step to grab a Github App auth token, so that PRs generated by this workflow # we use this step to grab a Github App auth token, so that PRs generated by this workflow
# run the GHA tests. # run the GHA tests.
- uses: actions/create-github-app-token@v2 - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
id: generate-token id: generate-token
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
with: with:
app-id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }} app-id: ${{ secrets.CIBUILDWHEEL_BOT_APP_ID }}
private-key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }} private-key: ${{ secrets.CIBUILDWHEEL_BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: wntrblm/nox@2025.10.16 - uses: wntrblm/nox@5a277b752f6094150e25237d47c34168e2b7526e # 2026.02.09
- name: "Run update: dependencies" - name: "Run update: dependencies"
run: nox --force-color -s update_constraints run: nox --force-color -s update_constraints
@@ -43,7 +50,7 @@ jobs:
- name: Create Pull Request - name: Create Pull Request
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel' if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
uses: peter-evans/create-pull-request@v7 uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
with: with:
commit-message: Update dependencies commit-message: Update dependencies
title: '[Bot] Update dependencies' title: '[Bot] Update dependencies'
+4 -2
View File
@@ -21,10 +21,12 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Update the ${{ env.TAG_NAME }} tag - name: Update the ${{ env.TAG_NAME }} tag
id: update-major-minor-tag id: update-major-minor-tag
uses: joerick/update-vX.Y-tag-action@v1.0 uses: joerick/update-vX.Y-tag-action@c4cefb60c33b82e4aa73a469e4acf30ee48d5812 # v1.0.2
with: with:
source-tag: ${{ env.TAG_NAME }} source-tag: ${{ env.TAG_NAME }}
+24
View File
@@ -0,0 +1,24 @@
name: zizmor - GitHub Actions Security Analysis
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
permissions: {}
jobs:
zizmor:
name: Run zizmor 🌈
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
+7
View File
@@ -112,3 +112,10 @@ site/
# PyCharm # PyCharm
.idea/ .idea/
# Lockfiles
*.lock
*.pylock
# OS files
.DS_Store
+13 -12
View File
@@ -1,7 +1,9 @@
repos: ci:
autoupdate_schedule: monthly
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0 rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks: hooks:
- id: check-case-conflict - id: check-case-conflict
- id: check-merge-conflict - id: check-merge-conflict
@@ -14,14 +16,14 @@ repos:
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.4 rev: 4924b0e01e032fea073ad04a1c5cfa7e4add0afb # frozen: v0.15.6
hooks: hooks:
- id: ruff-check - id: ruff-check
args: ["--fix", "--show-fixes"] args: ["--fix"]
- id: ruff-format - id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.18.2 rev: a66e98df7b4aeeb3724184b332785976d062b92e # frozen: v1.19.1
hooks: hooks:
- id: mypy - id: mypy
name: mypy 3.11 on cibuildwheel/ name: mypy 3.11 on cibuildwheel/
@@ -49,12 +51,12 @@ repos:
- uv - uv
- validate-pyproject - validate-pyproject
- id: mypy - id: mypy
name: mypy 3.13 name: mypy 3.14
args: ["--python-version=3.13"] args: ["--python-version=3.14"]
additional_dependencies: *mypy-dependencies additional_dependencies: *mypy-dependencies
- repo: https://github.com/shellcheck-py/shellcheck-py - repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1 rev: 745eface02aef23e168a8afb6b5737818efbea95 # frozen: v0.11.0.1
hooks: hooks:
- id: shellcheck - id: shellcheck
@@ -75,7 +77,7 @@ repos:
additional_dependencies: [cogapp>=3.5] additional_dependencies: [cogapp>=3.5]
- repo: https://github.com/codespell-project/codespell - repo: https://github.com/codespell-project/codespell
rev: v2.4.1 rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2
hooks: hooks:
- id: codespell - id: codespell
args: ["-w"] args: ["-w"]
@@ -83,14 +85,13 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.34.1 rev: 9f48a48aa91a6040d749ad68ec70907d907a5a7f # frozen: 0.37.0
hooks: hooks:
- id: check-dependabot - id: check-dependabot
- id: check-github-actions - id: check-github-actions
- id: check-github-workflows - id: check-github-workflows
- id: check-gitlab-ci - id: check-gitlab-ci
# Disabled due to schema issue for now: - id: check-readthedocs
# - id: check-readthedocs
- id: check-travis - id: check-travis
- id: check-jsonschema - id: check-jsonschema
name: Check projects name: Check projects
-79
View File
@@ -1,79 +0,0 @@
os: linux
dist: jammy
language: python
branches:
only:
- main
# only build the main branch or PR that explicitely want to test with Travis CI
if: (type = "push") OR (commit_message =~ /travis-ci/)
jobs:
include:
- name: Linux | x86_64 + i686 | Python 3.12
python: 3.12
services: docker
env:
- PYTHON=python
# a build using CIBW_ENABLE=all does not fit into Travis' time limit,
# so only the defaults are tested
- name: Linux | arm64 | Python 3.12
python: 3.12
services: docker
arch: arm64
env:
- PYTHON=python
- CIBW_ENABLE=all
- name: Linux | ppc64le | Python 3.12
python: 3.12
services: docker
arch: ppc64le
allow_failure: True
env:
- PYTHON=python
# skip test_manylinuxXXXX_only, it uses too much disk space
# c.f. https://travis-ci.community/t/running-out-of-disk-space-quota-when-using-docker-on-ppc64le/11634
- PYTEST_ADDOPTS='-k "not test_manylinuxXXXX_only"'
- CIBW_ENABLE=all
- name: Windows | x86_64 | Python 3.12
os: windows
language: shell
before_install:
# http://woshub.com/updating-trusted-root-certificates-in-windows-10
- certutil -generateSSTFromWU roots.sst
- powershell -Command 'Get-ChildItem -Path roots.sst | Import-Certificate -CertStoreLocation Cert:\LocalMachine\Root'
- rm -f roots.sst
- choco upgrade python3 -y --version 3.12.8 --limit-output --params "/InstallDir:C:\\Python312"
env:
- PYTHON=C:\\Python312\\python
# a build using CIBW_ENABLE=all does not fit into Travis' time limit,
# so only the defaults are tested
- name: Linux | s390x | Python 3.12
python: 3.12
services: docker
arch: s390x
allow_failure: True
env:
- PYTHON=python
- CIBW_ENABLE=all
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. --group test
script: |
# travis_wait disable the output while waiting
# use the same kind of tricks as in multibuild
(while true; do echo "travis_keep_alive"; sleep 300; done) &
SPINNER_PID=$!
disown
result=0
$PYTHON ./bin/run_tests.py --num-processes 2 || result=1
kill -9 ${SPINNER_PID}
test ${result} -eq 0
+5 -7
View File
@@ -1,11 +1,9 @@
This is a summary of the host Python versions and platforms covered by the different CI platforms: This is a summary of the host Python versions and platforms covered by the different CI platforms:
| | 3.11 | 3.12 | 3.13 | | | 3.11 | 3.12 | 3.13 | 3.14 |
|---------|----------------------------------|---------------------------------------------|----------------| |---------|----------------------------------|---------------------------------|----------------|----------------|
| Linux | Azure Pipelines / GitHub Actions | CircleCI¹ / Cirrus CI / GitLab¹ / Travis CI | GitHub Actions | | Linux | Azure Pipelines / GitHub Actions | CircleCI¹ / Cirrus CI / GitLab¹ | GitHub Actions | GitHub Actions |
| macOS | Azure Pipelines | CircleCI¹ / Cirrus CI / GitLab¹ | GitHub Actions | | macOS | Azure Pipelines | CircleCI¹ / Cirrus CI / GitLab¹ | GitHub Actions | |
| Windows | Azure Pipelines | Cirrus CI / GitLab¹ / Travis CI | GitHub Actions | | Windows | Azure Pipelines | Cirrus CI / GitLab¹ | GitHub Actions | |
> ¹ Runs a reduced set of tests to reduce CI load > ¹ Runs a reduced set of tests to reduce CI load
Non-x86 architectures are covered on Travis CI using Python 3.12.
+5 -20
View File
@@ -1,24 +1,9 @@
This project is licensed under the 'BSD 2-clause license'. Copyright 2017, Joe Rickerby and contributors. All rights reserved.
Copyright (c) 2017-2025, Joe Rickerby and contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+43 -49
View File
@@ -4,7 +4,6 @@ cibuildwheel
[![PyPI](https://img.shields.io/pypi/v/cibuildwheel.svg)](https://pypi.python.org/pypi/cibuildwheel) [![PyPI](https://img.shields.io/pypi/v/cibuildwheel.svg)](https://pypi.python.org/pypi/cibuildwheel)
[![Documentation Status](https://readthedocs.org/projects/cibuildwheel/badge/?version=stable)](https://cibuildwheel.pypa.io/en/stable/?badge=stable) [![Documentation Status](https://readthedocs.org/projects/cibuildwheel/badge/?version=stable)](https://cibuildwheel.pypa.io/en/stable/?badge=stable)
[![Actions Status](https://github.com/pypa/cibuildwheel/workflows/Test/badge.svg)](https://github.com/pypa/cibuildwheel/actions) [![Actions Status](https://github.com/pypa/cibuildwheel/workflows/Test/badge.svg)](https://github.com/pypa/cibuildwheel/actions)
[![Travis Status](https://img.shields.io/travis/com/pypa/cibuildwheel/main?logo=travis)](https://travis-ci.com/github/pypa/cibuildwheel)
[![CircleCI Status](https://img.shields.io/circleci/build/gh/pypa/cibuildwheel/main?logo=circleci)](https://circleci.com/gh/pypa/cibuildwheel) [![CircleCI Status](https://img.shields.io/circleci/build/gh/pypa/cibuildwheel/main?logo=circleci)](https://circleci.com/gh/pypa/cibuildwheel)
[![Azure Status](https://dev.azure.com/joerick0429/cibuildwheel/_apis/build/status/pypa.cibuildwheel?branchName=main)](https://dev.azure.com/joerick0429/cibuildwheel/_build/latest?definitionId=4&branchName=main) [![Azure Status](https://dev.azure.com/joerick0429/cibuildwheel/_apis/build/status/pypa.cibuildwheel?branchName=main)](https://dev.azure.com/joerick0429/cibuildwheel/_build/latest?definitionId=4&branchName=main)
@@ -15,7 +14,7 @@ cibuildwheel
Python wheels are great. Building them across **Mac, Linux, Windows**, on **multiple versions of Python**, is not. Python wheels are great. Building them across **Mac, Linux, Windows**, on **multiple versions of Python**, is not.
`cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports GitHub Actions, Azure Pipelines, Travis CI, CircleCI, and GitLab CI - and it builds and tests your wheels across all of your platforms. `cibuildwheel` is here to help. `cibuildwheel` runs on your CI server - currently it supports GitHub Actions, Azure Pipelines, CircleCI, and GitLab CI - and it builds and tests your wheels across all of your platforms.
What does it do? What does it do?
@@ -46,7 +45,7 @@ While cibuildwheel itself requires a recent Python version to run (we support th
<sup>⁵ manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.</sup><br> <sup>⁵ manylinux armv7l support is experimental. As there are no RHEL based image for this architecture, it's using an Ubuntu based image instead.</sup><br>
- Builds manylinux, musllinux, macOS, and Windows wheels for CPython, PyPy, and GraalPy - Builds manylinux, musllinux, macOS, and Windows wheels for CPython, PyPy, and GraalPy
- Works on GitHub Actions, Azure Pipelines, Travis CI, CircleCI, GitLab CI, and Cirrus CI - Works on GitHub Actions, Azure Pipelines, CircleCI, GitLab CI, and Cirrus CI
- Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate) - Bundles shared library dependencies on Linux and macOS through [auditwheel](https://github.com/pypa/auditwheel) and [delocate](https://github.com/matthew-brett/delocate)
- Runs your library's tests against the wheel-installed version of your library - Runs your library's tests against the wheel-installed version of your library
@@ -61,7 +60,6 @@ Usage
|-----------------|-------|-------|---------|-----------|-----------|-------------|---------|-----| |-----------------|-------|-------|---------|-----------|-----------|-------------|---------|-----|
| GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅⁴ | ✅³ | | GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅⁴ | ✅³ |
| Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² | ✅⁴ | ✅³ | | Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² | ✅⁴ | ✅³ |
| Travis CI | ✅ | | ✅ | ✅ | | | ✅⁴ | |
| CircleCI | ✅ | ✅ | | ✅ | ✅ | | ✅⁴ | ✅³ | | CircleCI | ✅ | ✅ | | ✅ | ✅ | | ✅⁴ | ✅³ |
| Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | | ✅⁴ | ✅³ | | Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | | ✅⁴ | ✅³ |
| Cirrus CI | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅⁴ | | | Cirrus CI | ✅ | ✅ | ✅ | ✅ | ✅ | | ✅⁴ | |
@@ -93,13 +91,15 @@ jobs:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-latest]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
# Used to host cibuildwheel # Used to host cibuildwheel
- uses: actions/setup-python@v5 - uses: actions/setup-python@v6
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==3.3.0 run: python -m pip install cibuildwheel==3.4.1
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
@@ -108,7 +108,7 @@ jobs:
# CIBW_SOME_OPTION: value # CIBW_SOME_OPTION: value
# ... # ...
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v6
with: with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl path: ./wheelhouse/*.whl
@@ -126,6 +126,11 @@ The following diagram summarises the steps that cibuildwheel takes on each platf
<sup>Explore an interactive version of this diagram [in the docs](https://cibuildwheel.pypa.io/en/stable/#how-it-works).</sup> <sup>Explore an interactive version of this diagram [in the docs](https://cibuildwheel.pypa.io/en/stable/#how-it-works).</sup>
> [!WARNING]
> Building and testing wheels executes arbitrary code from your project and its dependencies. Although cibuildwheel uses OCI containers and Pyodide for some builds, these provide no security guarantees - the code you're building and testing has full access to the environment that's invoking cibuildwheel.
>
> If you cannot trust all the code that's pulled in, maintain good security hygiene: keep the job that builds distributions separate from the job that uploads them to PyPI, handle secrets and credentials with care and rotate them regularly, and follow the principle of least privilege when granting permissions. Do not store sensitive data on CI runners.
<!--[[[cog from readme_options_table import get_table; print(get_table()) ]]]--> <!--[[[cog from readme_options_table import get_table; print(get_table()) ]]]-->
@@ -184,9 +189,9 @@ Here are some repos that use cibuildwheel.
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system | | [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. | | [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. | | [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform | | [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 | | [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [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. |
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. | | [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. | | [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS | | [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
@@ -195,9 +200,9 @@ Here are some repos that use cibuildwheel.
[duckdb]: https://github.com/duckdb/duckdb [duckdb]: https://github.com/duckdb/duckdb
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq [pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy [NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn [NCNN]: https://github.com/Tencent/ncnn
[Matplotlib]: https://github.com/matplotlib/matplotlib [Matplotlib]: https://github.com/matplotlib/matplotlib
[Tornado]: https://github.com/tornadoweb/tornado
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels [MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
[Prophet]: https://github.com/facebook/prophet [Prophet]: https://github.com/facebook/prophet
[Kivy]: https://github.com/kivy/kivy [Kivy]: https://github.com/kivy/kivy
@@ -230,6 +235,33 @@ Changelog
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] --> <!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v3.4.1
_2 April 2026_
- ⚠️ Building for the experimental CPython 3.13 free-threading variant is now deprecated. That functionality will be removed in the next minor release. The [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable) option `cpython-freethreading` is therefore also deprecated. Builds specifying `enable = "all"` no longer select `cpython-freethreading`. CPython 3.14 free-threading support remains available without the `enable` flag. (#2787)
- 🐛 iOS builds will no longer skip `repair-wheel-command` if it's defined in config (#2761)
- 🐛 Fix bug causing `uv` to fail when environments define PYTHON_VERSION or UV_PYTHON, conflicting with our venvs (#2795)
- ✨ cibuildwheel prints the selected build identifiers at the start of the build. (#2785)
- 🔐 The GitHub Action now references other actions with a full SHA (#2744)
### v3.4.0
_5 March 2026_
- 🌟 You can now build wheels using `uv` as a build frontend. This should improve performance, especially if your project has lots of build dependencies. To use, set [`build-frontend`](https://cibuildwheel.pypa.io/en/stable/options/#build-frontend) to `uv`. (#2322)
- ⚠️ We no longer support running on Travis CI. It may continue working but we don't run tests there anymore so we can't be sure. (#2682)
- ✨ Improvements to building rust wheels on Android (#2650)
- 🐛 Fix bug with the GitHub Action on Windows, where PATH was getting unnecessarily changed, causing issues with meson builds. (#2723)
- ✨ Add support for quiet setting on `build` and `uv` from the cibuildwheel `build-verbosity` setting. (#2737)
- 📚 Docs updates, including guidance on using Meson on Windows (#2718)
### v3.3.1
_5 January 2026_
- 🛠 Update dependencies and container pins, including updating to CPython 3.14.2. (#2708)
### v3.3.0 ### v3.3.0
_12 November 2025_ _12 November 2025_
@@ -252,45 +284,7 @@ _12 October 2025_
- 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613) - 🐛 Fix the default MACOSX_DEPLOYMENT_TARGET on Python 3.14 (#2613)
- 📚 Docs improvements (#2617) - 📚 Docs improvements (#2617)
### v3.2.0 <!-- [[[end]]] (sum: NOLMd9iLDC) -->
_22 September 2025_
- ✨ Adds GraalPy v25 (Python 3.12) support (#2597)
- 🛠 Update to CPython 3.14.0rc3 (#2602)
- 🛠 Adds CPython 3.14.0 prerelease support for Android, and a number of improvements to Android builds (#2568, #2591)
- 🛠 Improvements to testing on Android, passing environment markers when installing the venv, and providing more debug output when build-verbosity is set (#2575)
- ⚠️ PyPy 3.10 was moved to `pypy-eol` in the `enable` option, as it is now end-of-life. (#2521)
- 📚 Docs improvements (#2574, #2601, #2598)
### v3.1.4
_19 August 2025_
- ✨ Add a `--clean-cache` command to clean up our cache (#2489)
- 🛠 Update Python to 3.14rc2 and other patch version bumps (#2542, #2556)
- 🛠 Update Pyodide to 0.28.2 (#2562, #2558)
- 🐛 Fix resolution with `pyodide-build` when `dependency-versions` is set (#2548)
- 🐛 Set `CMAKE_FIND_ROOT_PATH_MODE_PACKAGE` to `BOTH` on Android (#2547)
- 🐛 Add `patchelf` dependency for platforms that can build Android wheels (#2552)
- 🐛 Ignore empty values for `CIBW_ARCHS` like most other environment variables (#2541)
- 💼 The `color` and `suggest_on_error` argparse options are now default in 3.14rc1+ (#2554)
- 💼 Use the virtualenv release URL instead of blob URL (should be more robust) (#2555)
- 🧪 For iOS, lowering to macos-14 is needed for now due to issues with GitHub's runner images (#2557)
- 🧪 Split out platforms iOS and Android in our tests (#2519)
- 🧪 Fix and enable doctests (#2546)
- 📚 Improve our docs on free-threading (#2549)
### v3.1.3
_1 August 2025_
- 🐛 Fix bug where "latest" dependencies couldn't update to pip 25.2 on Windows (#2537)
- 🧪 Use pytest-rerunfailures to improve some of our iOS/Android tests (#2527, #2539)
- 🧪 Remove some GraalPy Windows workarounds in our tests (#2501)
<!-- [[[end]]] (sum: vS54piNR4b) -->
--- ---
+58 -30
View File
@@ -28,17 +28,18 @@ branding:
runs: runs:
using: composite using: composite
steps: steps:
- uses: actions/setup-python@v6 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python id: python
with: with:
python-version: "3.11 - 3.13" python-version: "3.11 - 3.14"
update-environment: false update-environment: false
- id: cibw - id: cibw
run: | run: |
# Install cibuildwheel # Install cibuildwheel and build the command line
"${{ steps.python.outputs.python-path }}" -u << "EOF" "$PYTHON" -u << "EOF"
import os import os
import shlex
import shutil import shutil
import sys import sys
import venv import venv
@@ -46,9 +47,7 @@ runs:
from pathlib import Path from pathlib import Path
from subprocess import run from subprocess import run
EXTRAS = set(e.strip() for e in "${{ inputs.extras }}".split(",") if e.strip()) EXTRAS = set(e.strip() for e in os.environ.get("INPUT_EXTRAS", "").split(",") if e.strip())
if sys.platform == "linux":
EXTRAS.discard("uv")
class EnvBuilder(venv.EnvBuilder): class EnvBuilder(venv.EnvBuilder):
@@ -61,59 +60,88 @@ runs:
def post_setup(self, context): def post_setup(self, context):
super().post_setup(context) super().post_setup(context)
self.bin_path = Path(context.env_exe).parent self.bin_path = Path(context.env_exe).parent
install_spec = r"${{ github.action_path }}" install_spec = os.environ["GITHUB_ACTION_PATH"]
if EXTRAS: if EXTRAS:
install_spec += f"[{','.join(sorted(EXTRAS))}]" install_spec += f"[{','.join(sorted(EXTRAS))}]"
run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", install_spec], check=True) run([sys.executable, "-m", "pip", "--python", context.env_exe, "install", install_spec], check=True)
print("::group::Install cibuildwheel") print("::group::Install cibuildwheel")
venv_path = Path(r"${{ runner.temp }}") / "cibw" venv_path = Path(os.environ["RUNNER_TEMP"]) / "cibw"
if venv_path.exists(): if venv_path.exists():
shutil.rmtree(venv_path) shutil.rmtree(venv_path)
builder = EnvBuilder() builder = EnvBuilder()
builder.create(venv_path) builder.create(venv_path)
exposed_binaries = {"cibuildwheel"} exposed_binaries = {"cibuildwheel"}
if "uv" in EXTRAS: if "uv" in EXTRAS:
exposed_binaries.add("uv") exposed_binaries.add("uv")
clean_bin_path = builder.bin_path.parent / f"{builder.bin_path.name}.clean" clean_bin_path = builder.bin_path.parent / f"{builder.bin_path.name}.clean"
clean_bin_path.mkdir() clean_bin_path.mkdir()
for path in list(builder.bin_path.iterdir()): for path in list(builder.bin_path.iterdir()):
if path.stem in exposed_binaries: if path.stem in exposed_binaries:
try: try:
os.symlink(path, clean_bin_path / path.name) os.symlink(path, clean_bin_path / path.name)
except OSError: except OSError:
import shutil
shutil.copy2(path, clean_bin_path / path.name) shutil.copy2(path, clean_bin_path / path.name)
full_path = f"{clean_bin_path}{os.pathsep}{os.environ['PATH']}"
cibw_bin = [p for p in builder.bin_path.glob("cibuildwheel*") if p.stem == "cibuildwheel"][0]
# Build the command line
cmd_args = [str(cibw_bin), os.environ["INPUT_PACKAGE_DIR"]]
if output_dir := os.environ.get("INPUT_OUTPUT_DIR"):
cmd_args += ["--output-dir", output_dir]
if config_file := os.environ.get("INPUT_CONFIG_FILE"):
cmd_args += ["--config-file", config_file]
if only := os.environ.get("INPUT_ONLY"):
cmd_args += ["--only", only]
cmd_bash = shlex.join(cmd_args)
def pwsh_quote(text):
# Wrap in single quotes and double-up any existing single quotes
return "'" + str(text).replace("'", "''") + "'"
# Prepend '& ' so PowerShell executes the quoted binary path
cmd_pwsh = "& " + " ".join(pwsh_quote(arg) for arg in cmd_args)
with open(os.environ["GITHUB_OUTPUT"], "at") as f: with open(os.environ["GITHUB_OUTPUT"], "at") as f:
f.write(f"updated-path={full_path}\n") f.write(f"prepend-path={clean_bin_path}\n")
f.write(f"cmd-bash={cmd_bash}\n")
f.write(f"cmd-pwsh={cmd_pwsh}\n")
print("::endgroup::") print("::endgroup::")
EOF EOF
shell: bash shell: bash
env:
PYTHON: ${{ steps.python.outputs.python-path }}
INPUT_PACKAGE_DIR: ${{ inputs.package-dir }}
INPUT_OUTPUT_DIR: ${{ inputs.output-dir }}
INPUT_CONFIG_FILE: ${{ inputs.config-file }}
INPUT_ONLY: ${{ inputs.only }}
INPUT_EXTRAS: ${{ inputs.extras }}
# Redirecting stderr to stdout to fix interleaving issue in Actions. # Redirecting stderr to stdout to fix interleaving issue in Actions.
- run: > - run: |
cibuildwheel export PATH="$CIBW_PREPEND_PATH:$PATH"
"${{ inputs.package-dir }}" eval "$CIBW_CMD_BASH" 2>&1
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
2>&1
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: bash shell: bash
if: runner.os != 'Windows' if: runner.os != 'Windows'
env:
CIBW_PREPEND_PATH: ${{ steps.cibw.outputs.prepend-path }}
CIBW_CMD_BASH: ${{ steps.cibw.outputs.cmd-bash }}
# Windows needs powershell to interact nicely with Meson # Windows needs powershell to interact nicely with Meson
- run: > - run: |
cibuildwheel $env:PATH = "$env:CIBW_PREPEND_PATH;$env:PATH"
"${{ inputs.package-dir }}" Invoke-Expression $env:CIBW_CMD_PWSH
${{ inputs.output-dir != '' && format('--output-dir "{0}"', inputs.output-dir) || ''}}
${{ inputs.config-file != '' && format('--config-file "{0}"', inputs.config-file) || ''}}
${{ inputs.only != '' && format('--only "{0}"', inputs.only) || ''}}
env:
PATH: "${{ steps.cibw.outputs.updated-path }}"
shell: pwsh shell: pwsh
if: runner.os == 'Windows' if: runner.os == 'Windows'
env:
CIBW_PREPEND_PATH: ${{ steps.cibw.outputs.prepend-path }}
CIBW_CMD_PWSH: ${{ steps.cibw.outputs.cmd-pwsh }}
+3 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# /// script # /// script
# dependencies = ["click", "packaging"] # dependencies = ["click", "packaging", "prek"]
# /// # ///
@@ -139,7 +139,7 @@ def bump_version() -> None:
# run pre-commit to update the README changelog # run pre-commit to update the README changelog
subprocess.run( subprocess.run(
[ [
"pre-commit", "prek",
"run", "run",
"--files=docs/changelog.md", "--files=docs/changelog.md",
], ],
@@ -149,7 +149,7 @@ def bump_version() -> None:
# run pre-commit to check that no errors occurred on the second run # run pre-commit to check that no errors occurred on the second run
subprocess.run( subprocess.run(
[ [
"pre-commit", "prek",
"run", "run",
"--files=docs/changelog.md", "--files=docs/changelog.md",
], ],
+5 -4
View File
@@ -28,7 +28,6 @@ $defs:
description: How to inherit the parent's value. description: How to inherit the parent's value.
enable: enable:
enum: enum:
- cpython-experimental-riscv64
- cpython-freethreading - cpython-freethreading
- cpython-prerelease - cpython-prerelease
- graalpy - graalpy
@@ -58,21 +57,23 @@ properties:
type: string_array type: string_array
build-frontend: build-frontend:
default: default default: default
description: Set the tool to use to build, either "build" (default), "build[uv]", or "pip" description: Set the tool to use to build, either "build" (default), "build[uv]", "uv", or "pip"
oneOf: oneOf:
- enum: [pip, build, "build[uv]", default] - enum: [pip, build, "build[uv]", uv, default]
- type: string - type: string
pattern: '^pip; ?args:' pattern: '^pip; ?args:'
- type: string - type: string
pattern: '^build; ?args:' pattern: '^build; ?args:'
- type: string - type: string
pattern: '^build\\[uv\\]; ?args:' pattern: '^build\\[uv\\]; ?args:'
- type: string
pattern: '^uv; ?args:'
- type: object - type: object
additionalProperties: false additionalProperties: false
required: [name] required: [name]
properties: properties:
name: name:
enum: [pip, build, "build[uv]"] enum: [pip, build, "build[uv]", uv]
args: args:
type: array type: array
items: items:
+44 -14
View File
@@ -16,6 +16,8 @@ import click
DIR = Path(__file__).parent.parent.resolve() DIR = Path(__file__).parent.parent.resolve()
BuildBackend = typing.Literal["setuptools", "meson"]
def shell(cmd: str, *, check: bool, **kwargs: object) -> subprocess.CompletedProcess[str]: def shell(cmd: str, *, check: bool, **kwargs: object) -> subprocess.CompletedProcess[str]:
return subprocess.run([cmd], shell=True, check=check, **kwargs) # type: ignore[call-overload, no-any-return] return subprocess.run([cmd], shell=True, check=check, **kwargs) # type: ignore[call-overload, no-any-return]
@@ -27,11 +29,17 @@ def git_repo_has_changes() -> bool:
return unstaged_changes or staged_changes return unstaged_changes or staged_changes
def generate_basic_project(path: Path) -> None: def generate_project(path: Path, build_backend: BuildBackend) -> None:
sys.path.insert(0, "") sys.path.insert(0, "")
from test.test_projects.c import new_c_project # noqa: PLC0415 match build_backend:
case "meson":
from test.test_projects.meson import new_meson_project as new_project # noqa: PLC0415
case "setuptools":
from test.test_projects.setuptools import new_c_project as new_project # noqa: PLC0415
case _:
typing.assert_never(build_backend)
project = new_c_project() project = new_project()
project.generate(path) project.generate(path)
@@ -39,10 +47,10 @@ class CIService(typing.NamedTuple):
name: str name: str
dst_config_path: str dst_config_path: str
badge_md: str badge_md: str
config_file_transform: typing.Callable[[str], str] = lambda x: x # identity by default config_file_transform: typing.Callable[[str, str], str] = lambda x, _: x # identity by default
def github_config_file_transform(content: str) -> str: def github_config_file_transform(content: str, git_ref: str) -> str:
# one of the the github configs only builds on main, so we need to remove that restriction # one of the the github configs only builds on main, so we need to remove that restriction
# so our example build will run on the test branch. # so our example build will run on the test branch.
# #
@@ -61,6 +69,22 @@ def github_config_file_transform(content: str) -> str:
"push:", "push:",
content, content,
) )
# use the version of cibuildwheel from the current commit, not the latest
# release
# replace:
# """
# uses: pypa/cibuildwheel@v3.3.1
# """
# with:
# """
# uses: pypa/cibuildwheel@<latest commit hash>
# """
content = re.sub(
r"uses: pypa/cibuildwheel@v.*",
f"uses: pypa/cibuildwheel@{git_ref}",
content,
)
return content return content
@@ -110,20 +134,23 @@ def ci_service_for_config_file(config_file: Path) -> CIService:
@click.command() @click.command()
@click.argument("config_files", nargs=-1, type=click.Path()) @click.argument("config_files", nargs=-1, type=click.Path())
def run_example_ci_configs(config_files=None): @click.option("--build-backend", type=click.Choice(["setuptools", "meson"]), default="setuptools")
def run_example_ci_configs(
config_files: list[str], build_backend: BuildBackend = "setuptools"
) -> None:
""" """
Test the example configs. If no files are specified, will test Test the example configs. If no files are specified, will test
examples/*-minimal.yml examples/*-minimal.yml
""" """
if len(config_files) == 0: if len(config_files) == 0:
config_files = Path("examples").glob("*-minimal.yml") config_file_paths = list(Path("examples").glob("*-minimal.yml"))
else: else:
config_files = [Path(f) for f in config_files] config_file_paths = [Path(f) for f in config_files]
# check each CI service has at most 1 config file # check each CI service has at most 1 config file
configs_by_service = set() configs_by_service = set()
for config_file in config_files: for config_file in config_file_paths:
service = ci_service_for_config_file(config_file) service = ci_service_for_config_file(config_file)
if service.name in configs_by_service: if service.name in configs_by_service:
msg = "You cannot specify more than one config per CI service" msg = "You cannot specify more than one config per CI service"
@@ -137,6 +164,9 @@ def run_example_ci_configs(config_files=None):
previous_branch = shell( previous_branch = shell(
"git rev-parse --abbrev-ref HEAD", check=True, capture_output=True, encoding="utf8" "git rev-parse --abbrev-ref HEAD", check=True, capture_output=True, encoding="utf8"
).stdout.strip() ).stdout.strip()
git_ref = shell(
"git rev-parse HEAD", check=True, capture_output=True, encoding="utf8"
).stdout.strip()
timestamp = time.strftime("%Y-%m-%dT%H-%M-%S", time.gmtime()) timestamp = time.strftime("%Y-%m-%dT%H-%M-%S", time.gmtime())
branch_name = f"example-config-test---{previous_branch}-{timestamp}" branch_name = f"example-config-test---{previous_branch}-{timestamp}"
@@ -145,16 +175,16 @@ def run_example_ci_configs(config_files=None):
shell(f"git checkout --orphan {branch_name}", check=True) shell(f"git checkout --orphan {branch_name}", check=True)
example_project = Path("example_root") example_project = Path("example_root")
generate_basic_project(example_project) generate_project(example_project, build_backend=build_backend)
for config_file in config_files: for config_file in config_file_paths:
service = ci_service_for_config_file(config_file) service = ci_service_for_config_file(config_file)
dst_config_file = example_project / service.dst_config_path dst_config_file = example_project / service.dst_config_path
dst_config_file.parent.mkdir(parents=True, exist_ok=True) dst_config_file.parent.mkdir(parents=True, exist_ok=True)
contents = config_file.read_text(encoding="utf8") contents = config_file.read_text(encoding="utf8")
contents = service.config_file_transform(contents) contents = service.config_file_transform(contents, git_ref)
dst_config_file.write_text(contents, encoding="utf8") dst_config_file.write_text(contents, encoding="utf8")
subprocess.run(["git", "add", example_project], check=True) subprocess.run(["git", "add", example_project], check=True)
@@ -178,14 +208,14 @@ def run_example_ci_configs(config_files=None):
print("> ") print("> ")
print("> | Service | Config | Status |") print("> | Service | Config | Status |")
print("> |---|---|---|") print("> |---|---|---|")
for config_file in config_files: for config_file in config_file_paths:
service = ci_service_for_config_file(config_file) service = ci_service_for_config_file(config_file)
badge = service.badge_md.format( badge = service.badge_md.format(
branch=branch_name, branch_escaped=quote(branch_name, safe="") branch=branch_name, branch_escaped=quote(branch_name, safe="")
) )
print(f"> | {service.name} | `{config_file}` | {badge} |") print(f"> | {service.name} | `{config_file}` | {badge} |")
print("> ") print("> ")
print("> Generated by `bin/run_example_ci_config.py`") print(f"> Generated by `{' '.join(sys.argv)}`")
print() print()
print("---") print("---")
finally: finally:
+23 -21
View File
@@ -117,7 +117,7 @@ class GraalPyVersions:
self.releases = [r for r in releases if "graalpy_version" in r and "python_version" in r] self.releases = [r for r in releases if "graalpy_version" in r and "python_version" in r]
def update_version(self, identifier: str, spec: Specifier) -> ConfigUrl: def update_version(self, identifier: str, spec: Specifier) -> ConfigUrl | None:
if "x86_64" in identifier or "amd64" in identifier: if "x86_64" in identifier or "amd64" in identifier:
arch = "x86_64" arch = "x86_64"
elif "arm64" in identifier or "aarch64" in identifier: elif "arm64" in identifier or "aarch64" in identifier:
@@ -126,14 +126,14 @@ class GraalPyVersions:
msg = f"{identifier} not supported yet on GraalPy" msg = f"{identifier} not supported yet on GraalPy"
raise RuntimeError(msg) raise RuntimeError(msg)
gpspec_str = identifier.split("-")[0].split("_")[1] gpspec_str = identifier.split("-", maxsplit=1)[0].split("_")[1]
if "." not in gpspec_str and len(gpspec_str) == 3: if "." not in gpspec_str and len(gpspec_str) == 3:
gpspec_str = gpspec_str[:2] + "." + gpspec_str[-1] gpspec_str = gpspec_str[:2] + "." + gpspec_str[-1]
gpspec = Specifier(f"=={gpspec_str}.*") gpspec = Specifier(f"=={gpspec_str}.*")
releases = [r for r in self.releases if spec.contains(r["python_version"])] releases_tmp = (r for r in self.releases if spec.contains(r["python_version"]))
releases = [r for r in self.releases if gpspec.contains(r["graalpy_version"])] releases_tmp = (r for r in releases_tmp if gpspec.contains(r["graalpy_version"]))
releases = sorted(releases, key=lambda r: r["graalpy_version"]) releases = sorted(releases_tmp, key=lambda r: r["graalpy_version"])
if not releases: if not releases:
msg = f"GraalPy {arch} not found for {spec}!" msg = f"GraalPy {arch} not found for {spec}!"
@@ -155,18 +155,20 @@ class GraalPyVersions:
arch = "amd64" if arch == "x86_64" else "aarch64" arch = "amd64" if arch == "x86_64" else "aarch64"
ext = "zip" if "win" in identifier else "tar.gz" ext = "zip" if "win" in identifier else "tar.gz"
(url,) = ( urls = [
rf["browser_download_url"] rf["browser_download_url"]
for rf in release["assets"] for rf in release["assets"]
if rf["name"].endswith(f"{platform}-{arch}.{ext}") if rf["name"].endswith(f"{platform}-{arch}.{ext}")
and rf["name"].startswith(f"graalpy-{gpversion.major}") and rf["name"].startswith(f"graalpy-{gpversion.major}")
) ]
if urls:
return ConfigUrl( (url,) = urls
identifier=identifier, return ConfigUrl(
version=f"{version.major}.{version.minor}", identifier=identifier,
url=url, version=f"{version.major}.{version.minor}",
) url=url,
)
return None
class PyPyVersions: class PyPyVersions:
@@ -264,9 +266,11 @@ class CPythonVersions:
# Removing the prefix # Removing the prefix
version = Version(release["name"].removeprefix("Python ")) version = Version(release["name"].removeprefix("Python "))
self.versions_dict[version] = release["resource_uri"]
uri = int(release["resource_uri"].rstrip("/").split("/")[-1]) files_response = requests.get("https://www.python.org/api/v2/downloads/release_file/")
self.versions_dict[version] = uri files_response.raise_for_status()
self.files_info = files_response.json()
def update_version(self, identifier: str, spec: Specifier, file_ident: str) -> ConfigUrl | None: def update_version(self, identifier: str, spec: Specifier, file_ident: str) -> ConfigUrl | None:
# see note above on Specifier.filter # see note above on Specifier.filter
@@ -276,13 +280,9 @@ class CPythonVersions:
for new_version in sorted_versions: for new_version in sorted_versions:
# Find the first patch version that contains the requested file # Find the first patch version that contains the requested file
uri = self.versions_dict[new_version] uri = self.versions_dict[new_version]
response = requests.get( files = [rf for rf in self.files_info if rf["release"] == uri]
f"https://www.python.org/api/v2/downloads/release_file/?release={uri}"
)
response.raise_for_status()
file_info = response.json()
urls = [rf["url"] for rf in file_info if file_ident in rf["url"]] urls = [rf["url"] for rf in files if file_ident in rf["url"]]
if urls: if urls:
return ConfigUrl( return ConfigUrl(
identifier=identifier, identifier=identifier,
@@ -449,6 +449,8 @@ class AllVersions:
elif "macosx_arm64" in identifier: elif "macosx_arm64" in identifier:
config_update = self.macos_pypy_arm64.update_version_macos(spec) config_update = self.macos_pypy_arm64.update_version_macos(spec)
elif identifier.startswith("gp"): elif identifier.startswith("gp"):
if "macosx_x86_64" in identifier:
return
config_update = self.graalpy.update_version(identifier, spec) config_update = self.graalpy.update_version(identifier, spec)
elif "t-win32" in identifier and identifier.startswith("cp"): elif "t-win32" in identifier and identifier.startswith("cp"):
config_update = self.windows_t_32.update_version_windows(spec) config_update = self.windows_t_32.update_version_windows(spec)
+1 -1
View File
@@ -1 +1 @@
__version__ = "3.3.0" __version__ = "3.4.1"
+15 -10
View File
@@ -1,6 +1,7 @@
import argparse import argparse
import contextlib import contextlib
import dataclasses import dataclasses
import functools
import os import os
import shutil import shutil
import sys import sys
@@ -14,7 +15,6 @@ from tempfile import mkdtemp
from typing import Any, Literal, TextIO from typing import Any, Literal, TextIO
import cibuildwheel import cibuildwheel
import cibuildwheel.util
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture, allowed_architectures_check from cibuildwheel.architecture import Architecture, allowed_architectures_check
from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions
@@ -52,7 +52,7 @@ class Unbuffered:
self.stream.writelines(data) self.stream.writelines(data)
self.stream.flush() self.stream.flush()
def __getattr__(self, attr: str) -> Any: def __getattr__(self, attr: str) -> Any: # noqa: ANN401
return getattr(self.stream, attr) return getattr(self.stream, attr)
@@ -78,8 +78,13 @@ def main_inner(global_options: GlobalOptions) -> None:
`main_inner` is the same as `main`, but it raises FatalError exceptions `main_inner` is the same as `main`, but it raises FatalError exceptions
rather than exiting directly. rather than exiting directly.
""" """
# Default in 3.15+, only needed on 3.14
if sys.version_info >= (3, 14):
arg_parser = functools.partial(argparse.ArgumentParser, suggest_on_error=True)
else:
arg_parser = argparse.ArgumentParser
parser = argparse.ArgumentParser( parser = arg_parser(
description="Build wheels for all the platforms.", description="Build wheels for all the platforms.",
epilog=""" epilog="""
Most options are supplied via environment variables or in Most options are supplied via environment variables or in
@@ -426,17 +431,17 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
msg = "\n".join(error_list) msg = "\n".join(error_list)
raise errors.ConfigurationError(msg) raise errors.ConfigurationError(msg)
n = len(identifiers)
print(f"{n} build{'s' if n != 1 else ''} selected:")
print(", ".join(identifiers))
print()
print("Here we go!\n") print("Here we go!\n")
def detect_errors(*, options: Options, identifiers: Iterable[str]) -> Generator[str, None, None]: def detect_errors(*, options: Options, identifiers: Iterable[str]) -> Generator[str, None, None]:
# Check for deprecated CIBW_FREE_THREADED_SUPPORT environment variable # Check for deprecated CIBW_FREE_THREADED_SUPPORT environment variable
if "CIBW_FREE_THREADED_SUPPORT" in os.environ: if "CIBW_FREE_THREADED_SUPPORT" in os.environ:
yield ( yield "CIBW_FREE_THREADED_SUPPORT environment variable is no longer supported."
"CIBW_FREE_THREADED_SUPPORT environment variable is no longer supported. "
'Use tool.cibuildwheel.enable = ["cpython-freethreading"] in pyproject.toml '
"or set CIBW_ENABLE=cpython-freethreading instead."
)
# Deprecated {python} and {pip} # Deprecated {python} and {pip}
for option_name in ["test_command", "before_build"]: for option_name in ["test_command", "before_build"]:
@@ -463,9 +468,9 @@ def detect_warnings(*, options: Options) -> Generator[str, None, None]:
build_selector = options.globals.build_selector build_selector = options.globals.build_selector
test_selector = options.globals.test_selector test_selector = options.globals.test_selector
if EnableGroup.CPythonExperimentalRiscV64 in build_selector.enable: if EnableGroup.CPythonFreeThreading in build_selector.enable:
yield ( yield (
"'cpython-experimental-riscv64' enable is deprecated and will be removed in a future version. " "'cpython-freethreading' enable is deprecated and will be removed in a future version. "
"It should be removed from tool.cibuildwheel.enable in pyproject.toml " "It should be removed from tool.cibuildwheel.enable in pyproject.toml "
"or CIBW_ENABLE environment variable." "or CIBW_ENABLE environment variable."
) )
+49 -50
View File
@@ -6,11 +6,10 @@ import sys
import typing import typing
from collections.abc import Set from collections.abc import Set
from enum import StrEnum, auto from enum import StrEnum, auto
from typing import Final, Literal from typing import Final, Literal, Self
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.typing import PlatformName
from .typing import PlatformName
PRETTY_NAMES: Final[dict[PlatformName, str]] = { PRETTY_NAMES: Final[dict[PlatformName, str]] = {
"linux": "Linux", "linux": "Linux",
@@ -83,34 +82,34 @@ class Architecture(StrEnum):
arm64_iphonesimulator = auto() arm64_iphonesimulator = auto()
x86_64_iphonesimulator = auto() x86_64_iphonesimulator = auto()
@staticmethod @classmethod
def parse_config(config: str, platform: PlatformName) -> "set[Architecture]": def parse_config(cls, config: str, platform: PlatformName) -> set[Self]:
result = set() result = set()
for arch_str in re.split(r"[\s,]+", config): for arch_str in re.split(r"[\s,]+", config):
match arch_str: match arch_str:
case "auto": case "auto":
result |= Architecture.auto_archs(platform=platform) result |= cls.auto_archs(platform=platform)
case "native": case "native":
if native_arch := Architecture.native_arch(platform=platform): if native_arch := cls.native_arch(platform=platform):
result.add(native_arch) result.add(native_arch)
case "all": case "all":
result |= Architecture.all_archs(platform=platform) result |= cls.all_archs(platform=platform)
case "auto64": case "auto64":
result |= Architecture.bitness_archs(platform=platform, bitness="64") result |= cls.bitness_archs(platform=platform, bitness="64")
case "auto32": case "auto32":
result |= Architecture.bitness_archs(platform=platform, bitness="32") result |= cls.bitness_archs(platform=platform, bitness="32")
case _: case _:
try: try:
result.add(Architecture(arch_str)) result.add(cls(arch_str))
except ValueError as e: except ValueError as e:
msg = f"Invalid architecture '{arch_str}'" msg = f"Invalid architecture '{arch_str}'"
raise errors.ConfigurationError(msg) from e raise errors.ConfigurationError(msg) from e
return result return result
@staticmethod @classmethod
def native_arch(platform: PlatformName) -> "Architecture | None": def native_arch(cls, platform: PlatformName) -> Self | None:
native_machine = platform_module.machine() native_machine = platform_module.machine()
native_architecture = Architecture(native_machine) native_architecture = cls(native_machine)
# Cross-platform support. Used for --print-build-identifiers or docker builds. # Cross-platform support. Used for --print-build-identifiers or docker builds.
host_platform: PlatformName = ( host_platform: PlatformName = (
@@ -120,15 +119,15 @@ class Architecture(StrEnum):
) )
if platform == "pyodide": if platform == "pyodide":
return Architecture.wasm32 return cls.wasm32
elif platform == "ios": elif platform == "ios":
# Can only build for iOS on macOS. The "native" architecture is the # Can only build for iOS on macOS. The "native" architecture is the
# simulator for the macOS native platform. # simulator for the macOS native platform.
if host_platform == "macos": if host_platform == "macos":
if native_architecture == Architecture.x86_64: if native_architecture == cls.x86_64:
return Architecture.x86_64_iphonesimulator return cls.x86_64_iphonesimulator
else: else:
return Architecture.arm64_iphonesimulator return cls.arm64_iphonesimulator
else: else:
return None return None
@@ -140,64 +139,64 @@ class Architecture(StrEnum):
# can't build anything on this platform # can't build anything on this platform
return None return None
native_architecture = Architecture(synonym) native_architecture = cls(synonym)
return native_architecture return native_architecture
@staticmethod @classmethod
def auto_archs(platform: PlatformName) -> "set[Architecture]": def auto_archs(cls, platform: PlatformName) -> set[Self]:
native_arch = Architecture.native_arch(platform) native_arch = cls.native_arch(platform)
if native_arch is None: if native_arch is None:
return set() # can't build anything on this platform return set() # can't build anything on this platform
result = {native_arch} result = {native_arch}
match platform: match platform:
case "windows" if Architecture.AMD64 in result: case "windows" if cls.AMD64 in result:
result.add(Architecture.x86) result.add(cls.x86)
case "ios" if native_arch == Architecture.arm64_iphonesimulator: case "ios" if native_arch == cls.arm64_iphonesimulator:
# Also build the device wheel if we're on ARM64. # Also build the device wheel if we're on ARM64.
result.add(Architecture.arm64_iphoneos) result.add(cls.arm64_iphoneos)
return result return result
@staticmethod @classmethod
def all_archs(platform: PlatformName) -> "set[Architecture]": def all_archs(cls, platform: PlatformName) -> set[Self]:
all_archs_map = { all_archs_map = {
"linux": { "linux": {
Architecture.x86_64, cls.x86_64,
Architecture.i686, cls.i686,
Architecture.aarch64, cls.aarch64,
Architecture.ppc64le, cls.ppc64le,
Architecture.s390x, cls.s390x,
Architecture.armv7l, cls.armv7l,
Architecture.riscv64, cls.riscv64,
}, },
"macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2}, "macos": {cls.x86_64, cls.arm64, cls.universal2},
"windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64}, "windows": {cls.x86, cls.AMD64, cls.ARM64},
"pyodide": {Architecture.wasm32}, "pyodide": {cls.wasm32},
"android": {Architecture.x86_64, Architecture.arm64_v8a}, "android": {cls.x86_64, cls.arm64_v8a},
"ios": { "ios": {
Architecture.x86_64_iphonesimulator, cls.x86_64_iphonesimulator,
Architecture.arm64_iphonesimulator, cls.arm64_iphonesimulator,
Architecture.arm64_iphoneos, cls.arm64_iphoneos,
}, },
} }
return all_archs_map[platform] return all_archs_map[platform]
@staticmethod @classmethod
def bitness_archs(platform: PlatformName, bitness: Literal["64", "32"]) -> "set[Architecture]": def bitness_archs(cls, platform: PlatformName, bitness: Literal["64", "32"]) -> set[Self]:
# This map maps 64-bit architectures to their 32-bit equivalents. # This map maps 64-bit architectures to their 32-bit equivalents.
archs_map = { archs_map = {
Architecture.x86_64: Architecture.i686, cls.x86_64: cls.i686,
Architecture.AMD64: Architecture.x86, cls.AMD64: cls.x86,
Architecture.aarch64: Architecture.armv7l, cls.aarch64: cls.armv7l,
} }
native_arch = Architecture.native_arch(platform) native_arch = cls.native_arch(platform)
if native_arch is None: if native_arch is None:
return set() # can't build anything on this platform return set() # can't build anything on this platform
if native_arch == Architecture.wasm32: if native_arch == cls.wasm32:
return {native_arch} if bitness == "32" else set() return {native_arch} if bitness == "32" else set()
match bitness: match bitness:
@@ -207,7 +206,7 @@ class Architecture(StrEnum):
if native_arch in archs_map.values(): if native_arch in archs_map.values():
return {native_arch} return {native_arch}
elif native_arch in archs_map and platform in {"linux", "windows"}: elif native_arch in archs_map and platform in {"linux", "windows"}:
if native_arch == Architecture.aarch64 and not _check_aarch32_el0(): if native_arch == cls.aarch64 and not _check_aarch32_el0():
# If we're on aarch64, skip if we cannot build armv7l wheels. # If we're on aarch64, skip if we cannot build armv7l wheels.
return set() return set()
return {archs_map[native_arch]} return {archs_map[native_arch]}
+1 -1
View File
@@ -2,7 +2,7 @@ import os
import re import re
from enum import Enum from enum import Enum
from .util.helpers import strtobool from cibuildwheel.util.helpers import strtobool
ANSI_CODE_REGEX = re.compile(r"(\033\[[0-9;]*m)") ANSI_CODE_REGEX = re.compile(r"(\033\[[0-9;]*m)")
+2 -2
View File
@@ -5,7 +5,7 @@ from typing import Any, Protocol
import bashlex import bashlex
import bashlex.errors import bashlex.errors
from . import bashlex_eval from cibuildwheel import bashlex_eval
class EnvironmentParseError(Exception): class EnvironmentParseError(Exception):
@@ -131,7 +131,7 @@ class ParsedEnvironment:
def __repr__(self) -> str: def __repr__(self) -> str:
return f"{self.__class__.__name__}({[repr(a) for a in self.assignments]!r})" return f"{self.__class__.__name__}({[repr(a) for a in self.assignments]!r})"
def options_summary(self) -> Any: def options_summary(self) -> list[EnvironmentAssignment]:
return self.assignments return self.assignments
+1 -1
View File
@@ -62,7 +62,7 @@ def github_api_request(path: str, *, max_retries: int = 3) -> dict[str, Any]:
# pylint: disable=E1101 # pylint: disable=E1101
if ( if (
isinstance(e, urllib.error.HTTPError) isinstance(e, urllib.error.HTTPError)
and (e.code == 403 or e.code == 429) and (e.code in {403, 429})
and e.headers.get("x-ratelimit-remaining") == "0" and e.headers.get("x-ratelimit-remaining") == "0"
): ):
reset_time = int(e.headers.get("x-ratelimit-reset", 0)) reset_time = int(e.headers.get("x-ratelimit-reset", 0))
+11 -11
View File
@@ -4,10 +4,10 @@ import typing
from collections.abc import Sequence from collections.abc import Sequence
from typing import Literal, Self, get_args from typing import Literal, Self, get_args
from .logger import log from cibuildwheel.logger import log
from .util.helpers import parse_key_value_string from cibuildwheel.util.helpers import parse_key_value_string
BuildFrontendName = Literal["pip", "build", "build[uv]"] BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"]
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
@@ -36,13 +36,13 @@ class BuildFrontendConfig:
return {"name": self.name, "args": repr(self.args)} return {"name": self.name, "args": repr(self.args)}
def _get_verbosity_flags(level: int, frontend: BuildFrontendName) -> list[str]: def _get_verbosity_flags(level: int, frontend: BuildFrontendName, *, py38: bool) -> list[str]:
if level < 0: if level < 0:
if frontend == "pip": if frontend.startswith("build") and py38:
return ["-" + -level * "q"] msg = f"build_verbosity {level} is not supported for {frontend} frontend. Ignoring."
log.warning(msg)
msg = f"build_verbosity {level} is not supported for {frontend} frontend. Ignoring." return []
log.warning(msg) return ["-" + -level * "q"]
if level > 0: if level > 0:
if frontend == "pip": if frontend == "pip":
@@ -75,10 +75,10 @@ def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str]
def get_build_frontend_extra_flags( def get_build_frontend_extra_flags(
build_frontend: BuildFrontendConfig, verbosity_level: int, config_settings: str build_frontend: BuildFrontendConfig, verbosity_level: int, config_settings: str, *, py38: bool
) -> list[str]: ) -> list[str]:
return [ return [
*_split_config_settings(config_settings), *_split_config_settings(config_settings),
*build_frontend.args, *build_frontend.args,
*_get_verbosity_flags(verbosity_level, build_frontend.name), *_get_verbosity_flags(verbosity_level, build_frontend.name, py38=py38),
] ]
+2 -2
View File
@@ -15,10 +15,10 @@ from typing import IO, TYPE_CHECKING, AnyStr, Final, Literal
import humanize import humanize
from .ci import CIProvider, detect_ci_provider, filter_ansi_codes from cibuildwheel.ci import CIProvider, detect_ci_provider, filter_ansi_codes
if TYPE_CHECKING: if TYPE_CHECKING:
from .options import Options from cibuildwheel.options import Options
FoldPattern = tuple[str, str] FoldPattern = tuple[str, str]
DEFAULT_FOLD_PATTERN: Final[FoldPattern] = ("{name}", "") DEFAULT_FOLD_PATTERN: Final[FoldPattern] = ("{name}", "")
+7 -7
View File
@@ -16,12 +16,12 @@ from pathlib import Path, PurePath, PurePosixPath
from types import TracebackType from types import TracebackType
from typing import IO, Literal, Self, assert_never from typing import IO, Literal, Self, assert_never
from .ci import CIProvider, detect_ci_provider from cibuildwheel.ci import CIProvider, detect_ci_provider
from .errors import OCIEngineTooOldError from cibuildwheel.errors import OCIEngineTooOldError
from .logger import log from cibuildwheel.logger import log
from .typing import PathOrStr from cibuildwheel.typing import PathOrStr
from .util.cmd import call from cibuildwheel.util.cmd import call
from .util.helpers import FlexibleVersion, parse_key_value_string, strtobool from cibuildwheel.util.helpers import FlexibleVersion, parse_key_value_string, strtobool
ContainerEngineName = Literal["docker", "podman"] ContainerEngineName = Literal["docker", "podman"]
@@ -37,7 +37,7 @@ class OCIPlatform(Enum):
S390X = "linux/s390x" S390X = "linux/s390x"
@classmethod @classmethod
def native(cls) -> "OCIPlatform": def native(cls) -> Self:
"""Return the current OCI platform, or raise ValueError if unknown.""" """Return the current OCI platform, or raise ValueError if unknown."""
arch = platform.machine().lower() arch = platform.machine().lower()
mapping = { mapping = {
+17 -15
View File
@@ -14,18 +14,18 @@ from typing import Any, Final, Literal, Self, assert_never
from packaging.specifiers import SpecifierSet from packaging.specifiers import SpecifierSet
from . import errors from cibuildwheel import errors
from .architecture import Architecture from cibuildwheel.architecture import Architecture
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment from cibuildwheel.environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from .frontend import BuildFrontendConfig from cibuildwheel.frontend import BuildFrontendConfig
from .logger import log from cibuildwheel.logger import log
from .oci_container import OCIContainerEngineConfig from cibuildwheel.oci_container import OCIContainerEngineConfig
from .projectfiles import get_requires_python_str, resolve_dependency_groups from cibuildwheel.projectfiles import get_requires_python_str, resolve_dependency_groups
from .selector import BuildSelector, EnableGroup, TestSelector, selector_matches from cibuildwheel.selector import BuildSelector, EnableGroup, TestSelector, selector_matches
from .typing import PLATFORMS, PlatformName from cibuildwheel.typing import PLATFORMS, PlatformName
from .util import resources from cibuildwheel.util import resources
from .util.helpers import format_safe, parse_key_value_string, strtobool, unwrap from cibuildwheel.util.helpers import format_safe, parse_key_value_string, strtobool, unwrap
from .util.packaging import DependencyConstraints from cibuildwheel.util.packaging import DependencyConstraints
MANYLINUX_ARCHS: Final[tuple[str, ...]] = ( MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64", "x86_64",
@@ -686,6 +686,8 @@ class Options:
skip_config = "" skip_config = ""
architectures = Architecture.all_archs(self.platform) architectures = Architecture.all_archs(self.platform)
enable |= EnableGroup.all_groups() enable |= EnableGroup.all_groups()
if args.only.startswith("cp313t-"):
enable.add(EnableGroup.CPythonFreeThreading)
build_selector = BuildSelector( build_selector = BuildSelector(
build_config=build_config, build_config=build_config,
@@ -987,8 +989,8 @@ class Options:
def option_summary( def option_summary(
self, self,
option_name: str, option_name: str,
option_value: Any, option_value: Any, # noqa: ANN401
default_value: Any, default_value: Any, # noqa: ANN401
overrides: Mapping[str, Any] | None = None, overrides: Mapping[str, Any] | None = None,
skip_unset: bool = False, skip_unset: bool = False,
) -> str | None: ) -> str | None:
@@ -1040,7 +1042,7 @@ class Options:
return value return value
@staticmethod @staticmethod
def option_summary_value(option_value: Any) -> str: def option_summary_value(option_value: Any) -> str: # noqa: ANN401
if hasattr(option_value, "options_summary"): if hasattr(option_value, "options_summary"):
option_value = option_value.options_summary() option_value = option_value.options_summary()
+7 -12
View File
@@ -1,19 +1,14 @@
from __future__ import annotations
import sys import sys
from typing import TYPE_CHECKING, Final, Protocol from collections.abc import Sequence
from pathlib import Path
from typing import Final, Protocol
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture
from cibuildwheel.options import Options
from cibuildwheel.platforms import android, ios, linux, macos, pyodide, windows from cibuildwheel.platforms import android, ios, linux, macos, pyodide, windows
from cibuildwheel.selector import BuildSelector
if TYPE_CHECKING: from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
from collections.abc import Sequence
from pathlib import Path
from cibuildwheel.architecture import Architecture
from cibuildwheel.options import Options
from cibuildwheel.selector import BuildSelector
from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
class PlatformModule(Protocol): class PlatformModule(Protocol):
+91 -36
View File
@@ -7,7 +7,7 @@ import shlex
import shutil import shutil
import subprocess import subprocess
import sysconfig import sysconfig
from collections.abc import Iterable, Iterator from collections.abc import Iterable, Iterator, MutableMapping
from dataclasses import dataclass from dataclasses import dataclass
from os.path import relpath from os.path import relpath
from pathlib import Path from pathlib import Path
@@ -22,19 +22,19 @@ from elftools.common.exceptions import ELFError
from elftools.elf.elffile import ELFFile from elftools.elf.elffile import ELFFile
from filelock import FileLock from filelock import FileLock
from .. import errors, platforms # pylint: disable=cyclic-import from cibuildwheel import errors, platforms # pylint: disable=cyclic-import
from ..architecture import Architecture, arch_synonym from cibuildwheel.architecture import Architecture, arch_synonym
from ..frontend import get_build_frontend_extra_flags, parse_config_settings from cibuildwheel.frontend import get_build_frontend_extra_flags, parse_config_settings
from ..logger import log from cibuildwheel.logger import log
from ..options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
from ..util.helpers import prepare_command from cibuildwheel.util.helpers import prepare_command
from ..util.packaging import find_compatible_wheel from cibuildwheel.util.packaging import find_compatible_wheel
from ..util.python_build_standalone import create_python_build_standalone_environment from cibuildwheel.util.python_build_standalone import create_python_build_standalone_environment
from ..venv import constraint_flags, find_uv, virtualenv from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
ANDROID_TRIPLET = { ANDROID_TRIPLET = {
"arm64_v8a": "aarch64-linux-android", "arm64_v8a": "aarch64-linux-android",
@@ -190,7 +190,7 @@ def setup_env(
""" """
log.step("Setting up build environment...") log.step("Setting up build environment...")
build_frontend = build_options.build_frontend.name build_frontend = build_options.build_frontend.name
use_uv = build_frontend == "build[uv]" use_uv = build_frontend in {"build[uv]", "uv"}
uv_path = find_uv() uv_path = find_uv()
if use_uv and uv_path is None: if use_uv and uv_path is None:
msg = "uv not found" msg = "uv not found"
@@ -228,8 +228,8 @@ def setup_env(
android_env = setup_android_env(config, python_dir, venv_dir, build_env) android_env = setup_android_env(config, python_dir, venv_dir, build_env)
# Install build tools # Install build tools
if build_frontend not in {"build", "build[uv]"}: if build_frontend not in {"build", "build[uv]", "uv"}:
msg = "Android requires the build frontend to be 'build'" msg = "Android requires the build frontend to be 'build' or 'uv'"
raise errors.FatalError(msg) raise errors.FatalError(msg)
call(*pip, "install", "build", *constraint_flags(dependency_constraint), env=build_env) call(*pip, "install", "build", *constraint_flags(dependency_constraint), env=build_env)
@@ -390,6 +390,9 @@ def setup_android_env(
for key in ["CFLAGS", "CXXFLAGS"]: for key in ["CFLAGS", "CXXFLAGS"]:
android_env[key] += " " + opt android_env[key] += " " + opt
# Cargo target linker needs to be specified after CC is set
setup_rust(config, python_dir, android_env)
# Format the environment so it can be pasted into a shell when debugging. # Format the environment so it can be pasted into a shell when debugging.
for key, value in sorted(android_env.items()): for key, value in sorted(android_env.items()):
if os.environ.get(key) != value: if os.environ.get(key) != value:
@@ -398,6 +401,34 @@ def setup_android_env(
return android_env return android_env
def setup_rust(
config: PythonConfiguration,
python_dir: Path,
env: MutableMapping[str, str],
) -> None:
cargo_target = android_triplet(config.identifier)
# CARGO_BUILD_TARGET is the variable used by Cargo and setuptools_rust
env["CARGO_BUILD_TARGET"] = cargo_target
# The linker needs to be specified after CC is set by android-env.sh
cargo_target_linker_env_name = f"CARGO_TARGET_{cargo_target.upper().replace('-', '_')}_LINKER"
# CC has already been set by calling android.py (it calls android-env.sh)
env[cargo_target_linker_env_name] = env["CC"]
# All Python extension modules must be explicitly linked against libpython3.x.so when building for Android.
# See: https://peps.python.org/pep-0738/#linkage
# For projects using PyO3, this requires setting PYO3_CROSS_LIB_DIR to the directory containing libpython3.x.so.
# See: https://pyo3.rs/v0.27.1/building-and-distribution.html#cross-compiling
env["PYO3_CROSS_LIB_DIR"] = str(python_dir / "prefix" / "lib")
venv_bin = Path(env["VIRTUAL_ENV"]) / "bin"
for tool in ["cargo", "rustup"]:
shim_path = venv_bin / tool
shutil.copy(resources.PATH / "_rust_shim.py", shim_path)
shim_path.chmod(0o755)
def before_build(state: BuildState) -> None: def before_build(state: BuildState) -> None:
if state.options.before_build: if state.options.before_build:
log.step("Running before_build...") log.step("Running before_build...")
@@ -411,22 +442,46 @@ def before_build(state: BuildState) -> None:
def build_wheel(state: BuildState) -> Path: def build_wheel(state: BuildState) -> Path:
log.step("Building wheel...") log.step("Building wheel...")
built_wheel_dir = state.build_path / "built_wheel" built_wheel_dir = state.build_path / "built_wheel"
call( match state.options.build_frontend.name:
"python", case "build" | "build[uv]":
"-m", call(
"build", "python",
state.options.package_dir, "-m",
"--wheel", "build",
"--no-isolation", state.options.package_dir,
"--skip-dependency-check", "--wheel",
f"--outdir={built_wheel_dir}", "--no-isolation",
*get_build_frontend_extra_flags( "--skip-dependency-check",
state.options.build_frontend, f"--outdir={built_wheel_dir}",
state.options.build_verbosity, *get_build_frontend_extra_flags(
state.options.config_settings, state.options.build_frontend,
), state.options.build_verbosity,
env=state.android_env, state.options.config_settings,
) py38=False,
),
env=state.android_env,
)
case "uv":
uv_path = find_uv()
assert uv_path is not None
call(
uv_path,
"build",
state.options.package_dir,
"--wheel",
"--no-build-isolation",
f"--out-dir={built_wheel_dir}",
*get_build_frontend_extra_flags(
state.options.build_frontend,
state.options.build_verbosity,
state.options.config_settings,
py38=False,
),
env=state.android_env,
)
case x:
msg = f"Invalid build backend {x!r}"
raise AssertionError(msg)
built_wheels = list(built_wheel_dir.glob("*.whl")) built_wheels = list(built_wheel_dir.glob("*.whl"))
if len(built_wheels) != 1: if len(built_wheels) != 1:
@@ -634,7 +689,7 @@ def test_wheel(state: BuildState, wheel: Path, *, build_frontend: str) -> None:
) )
# Android doesn't support placeholders in the test command. # Android doesn't support placeholders in the test command.
if any(("{" + placeholder + "}") in test_command for placeholder in ["project", "package"]): if any(("{" + placeholder + "}") in test_command for placeholder in ("project", "package")):
msg = ( msg = (
f"Test command {test_command!r} with a " f"Test command {test_command!r} with a "
"'{project}' or '{package}' placeholder is not supported on Android, " "'{project}' or '{package}' placeholder is not supported on Android, "
@@ -644,12 +699,12 @@ def test_wheel(state: BuildState, wheel: Path, *, build_frontend: str) -> None:
# Parse test-command. # Parse test-command.
test_args = shlex.split(test_command) test_args = shlex.split(test_command)
if test_args[0] in ["python", "python3"] and any(arg in test_args for arg in ["-c", "-m"]): if test_args[0] in {"python", "python3"} and any(arg in test_args for arg in ("-c", "-m")):
# Forward the args to the CPython testbed script. We require '-c' or '-m' # Forward the args to the CPython testbed script. We require '-c' or '-m'
# to be in the command, because without those flags, the testbed script # to be in the command, because without those flags, the testbed script
# will prepend '-m test', which will run Python's own test suite. # will prepend '-m test', which will run Python's own test suite.
del test_args[0] del test_args[0]
elif test_args[0] in ["pytest"]: elif test_args[0] == "pytest":
# We transform some commands into the `python -m` form, but this is deprecated. # We transform some commands into the `python -m` form, but this is deprecated.
msg = ( msg = (
f"Test command {test_command!r} is not supported on Android. " f"Test command {test_command!r} is not supported on Android. "
+54 -38
View File
@@ -1,5 +1,3 @@
from __future__ import annotations
import dataclasses import dataclasses
import os import os
import platform import platform
@@ -8,39 +6,26 @@ import shutil
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from collections.abc import Sequence, Set
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, assert_never from typing import assert_never
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..frontend import ( from cibuildwheel.architecture import Architecture
BuildFrontendName, from cibuildwheel.environment import ParsedEnvironment
get_build_frontend_extra_flags, from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
) from cibuildwheel.logger import log
from ..logger import log from cibuildwheel.options import Options
from ..util import resources from cibuildwheel.platforms.macos import install_cpython as install_build_cpython
from ..util.cmd import call, shell, split_command from cibuildwheel.selector import BuildSelector
from ..util.file import ( from cibuildwheel.util import resources
CIBW_CACHE_PATH, from cibuildwheel.util.cmd import call, shell, split_command
copy_test_sources, from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
download, from cibuildwheel.util.helpers import prepare_command, unwrap_preserving_paragraphs
move_file, from cibuildwheel.util.packaging import find_compatible_wheel
) from cibuildwheel.venv import constraint_flags, virtualenv
from ..util.helpers import prepare_command, unwrap_preserving_paragraphs
from ..util.packaging import (
find_compatible_wheel,
)
from ..venv import constraint_flags, virtualenv
from .macos import install_cpython as install_build_cpython
if TYPE_CHECKING:
from collections.abc import Sequence, Set
from ..architecture import Architecture
from ..environment import ParsedEnvironment
from ..options import Options
from ..selector import BuildSelector
@dataclasses.dataclass(frozen=True, kw_only=True) @dataclasses.dataclass(frozen=True, kw_only=True)
@@ -284,7 +269,8 @@ def setup_python(
build_frontend: BuildFrontendName, build_frontend: BuildFrontendName,
xbuild_tools: Sequence[str] | None, xbuild_tools: Sequence[str] | None,
) -> tuple[Path, dict[str, str]]: ) -> tuple[Path, dict[str, str]]:
if build_frontend == "build[uv]": # Not using set because mypy can't narrow it
if build_frontend == "build[uv]" or build_frontend == "uv": # noqa: PLR1714
msg = "uv doesn't support iOS" msg = "uv doesn't support iOS"
raise errors.FatalError(msg) raise errors.FatalError(msg)
@@ -441,7 +427,8 @@ def build(options: Options, tmp_path: Path) -> None:
build_options = options.build_options(config.identifier) build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend build_frontend = build_options.build_frontend
# uv doesn't support iOS # uv doesn't support iOS
if build_frontend.name == "build[uv]": # Not using set because mypy can't narrow it
if build_frontend.name == "build[uv]" or build_frontend.name == "uv": # noqa: PLR1714
msg = "uv doesn't support iOS" msg = "uv doesn't support iOS"
raise errors.FatalError(msg) raise errors.FatalError(msg)
@@ -450,6 +437,7 @@ def build(options: Options, tmp_path: Path) -> None:
identifier_tmp_dir = tmp_path / config.identifier identifier_tmp_dir = tmp_path / config.identifier
identifier_tmp_dir.mkdir() identifier_tmp_dir.mkdir()
built_wheel_dir = identifier_tmp_dir / "built_wheel" built_wheel_dir = identifier_tmp_dir / "built_wheel"
repaired_wheel_dir = identifier_tmp_dir / "repaired_wheel"
constraints_path = build_options.dependency_constraints.get_for_python_version( constraints_path = build_options.dependency_constraints.get_for_python_version(
version=config.version, tmp_dir=identifier_tmp_dir version=config.version, tmp_dir=identifier_tmp_dir
@@ -487,7 +475,10 @@ def build(options: Options, tmp_path: Path) -> None:
built_wheel_dir.mkdir() built_wheel_dir.mkdir()
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend,
build_options.build_verbosity,
build_options.config_settings,
py38=False,
) )
match build_frontend.name: match build_frontend.name:
@@ -520,11 +511,36 @@ def build(options: Options, tmp_path: Path) -> None:
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
test_wheel = built_wheel = next(built_wheel_dir.glob("*.whl")) built_wheel = next(built_wheel_dir.glob("*.whl"))
if built_wheel.name.endswith("none-any.whl"): if built_wheel.name.endswith("none-any.whl"):
raise errors.NonPlatformWheelError() raise errors.NonPlatformWheelError()
repaired_wheel_dir.mkdir()
if build_options.repair_command:
log.step("Repairing wheel...")
repair_command_prepared = prepare_command(
build_options.repair_command,
wheel=built_wheel,
dest_dir=repaired_wheel_dir,
package=build_options.package_dir,
project=".",
)
shell(repair_command_prepared, env=env)
else:
shutil.move(str(built_wheel), repaired_wheel_dir)
try:
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
except StopIteration:
raise errors.RepairStepProducedNoWheelError() from None
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
test_wheel = repaired_wheel
log.step_end() log.step_end()
if build_options.test_command and build_options.test_selector(config.identifier): if build_options.test_command and build_options.test_selector(config.identifier):
@@ -692,11 +708,11 @@ def build(options: Options, tmp_path: Path) -> None:
# We're all done here; move it to output (overwrite existing) # We're all done here; move it to output (overwrite existing)
output_wheel: Path | None = None output_wheel: Path | None = None
if compatible_wheel is None: if compatible_wheel is None:
output_wheel = build_options.output_dir.joinpath(built_wheel.name) output_wheel = build_options.output_dir.joinpath(repaired_wheel.name)
moved_wheel = move_file(built_wheel, output_wheel) moved_wheel = move_file(repaired_wheel, output_wheel)
if moved_wheel != output_wheel.resolve(): if moved_wheel != output_wheel.resolve():
log.warning( log.warning(
f"{built_wheel} was moved to {moved_wheel} instead of {output_wheel}" f"{repaired_wheel} was moved to {moved_wheel} instead of {output_wheel}"
) )
built_wheels.append(output_wheel) built_wheels.append(output_wheel)
+31 -14
View File
@@ -8,20 +8,20 @@ from collections.abc import Iterable, Iterator, Sequence, Set
from pathlib import Path, PurePath, PurePosixPath from pathlib import Path, PurePath, PurePosixPath
from typing import TYPE_CHECKING, assert_never from typing import TYPE_CHECKING, assert_never
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..frontend import get_build_frontend_extra_flags from cibuildwheel.frontend import get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from ..options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.file import copy_test_sources from cibuildwheel.util.file import copy_test_sources
from ..util.helpers import prepare_command, unwrap from cibuildwheel.util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel from cibuildwheel.util.packaging import find_compatible_wheel
if TYPE_CHECKING: if TYPE_CHECKING:
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
ARCHITECTURE_OCI_PLATFORM_MAP = { ARCHITECTURE_OCI_PLATFORM_MAP = {
Architecture.x86_64: OCIPlatform.AMD64, Architecture.x86_64: OCIPlatform.AMD64,
@@ -207,7 +207,7 @@ def build_in_container(
local_identifier_tmp_dir = local_tmp_dir / config.identifier local_identifier_tmp_dir = local_tmp_dir / config.identifier
build_options = options.build_options(config.identifier) build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "build[uv]" use_uv = build_frontend.name in {"build[uv]", "uv"}
pip = ["uv", "pip"] if use_uv else ["pip"] pip = ["uv", "pip"] if use_uv else ["pip"]
log.step("Setting up build environment...") log.step("Setting up build environment...")
@@ -274,7 +274,10 @@ def build_in_container(
container.call(["mkdir", "-p", built_wheel_dir]) container.call(["mkdir", "-p", built_wheel_dir])
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend,
build_options.build_verbosity,
build_options.config_settings,
py38=config.identifier[1:].startswith("p38"),
) )
match build_frontend.name: match build_frontend.name:
@@ -307,6 +310,19 @@ def build_in_container(
], ],
env=env, env=env,
) )
case "uv":
container.call(
[
"uv",
"build",
f"--python={python_bin / 'python'}",
container_package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
],
env=env,
)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -509,6 +525,7 @@ def _matches_prepared_command(error_cmd: Sequence[str], command_template: str) -
def troubleshoot(options: Options, error: Exception) -> None: def troubleshoot(options: Options, error: Exception) -> None:
if isinstance(error, subprocess.CalledProcessError) and ( if isinstance(error, subprocess.CalledProcessError) and (
error.cmd[0:4] == ["python", "-m", "pip", "wheel"] error.cmd[0:4] == ["python", "-m", "pip", "wheel"]
or error.cmd[0:2] == ["uv", "build"]
or error.cmd[0:3] == ["python", "-m", "build"] or error.cmd[0:3] == ["python", "-m", "build"]
or _matches_prepared_command( or _matches_prepared_command(
error.cmd, options.build_options(None).repair_command error.cmd, options.build_options(None).repair_command
+54 -24
View File
@@ -15,25 +15,20 @@ from typing import Literal, assert_never
from filelock import FileLock from filelock import FileLock
from packaging.version import Version from packaging.version import Version
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..ci import detect_ci_provider from cibuildwheel.ci import detect_ci_provider
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import BuildFrontendName, get_build_frontend_extra_flags from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import ( from cibuildwheel.util.file import CIBW_CACHE_PATH, copy_test_sources, download, move_file
CIBW_CACHE_PATH, from cibuildwheel.util.helpers import prepare_command, unwrap
copy_test_sources, from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
download, from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
move_file,
)
from ..util.helpers import prepare_command, unwrap
from ..util.packaging import find_compatible_wheel, get_pip_version
from ..venv import constraint_flags, find_uv, virtualenv
@functools.cache @functools.cache
@@ -141,7 +136,8 @@ def install_cpython(_tmp: Path, version: str, url: str, free_threading: bool) ->
# let the user know & provide a link to the installer # let the user know & provide a link to the installer
msg = inspect.cleandoc( msg = inspect.cleandoc(
f""" f"""
Error: CPython {version} is not installed. Framework CPython {version} not detected as installed in:
{installation_path}
cibuildwheel will not perform system-wide installs when running outside of CI. cibuildwheel will not perform system-wide installs when running outside of CI.
To build locally, install CPython {version} on this machine, or, disable this To build locally, install CPython {version} on this machine, or, disable this
version of Python using CIBW_SKIP=cp{version.replace(".", "")}-macosx_* version of Python using CIBW_SKIP=cp{version.replace(".", "")}-macosx_*
@@ -150,7 +146,7 @@ def install_cpython(_tmp: Path, version: str, url: str, free_threading: bool) ->
""" """
) )
raise errors.FatalError(msg) raise errors.FatalError(msg)
python_filename = url.split("/")[-1] python_filename = url.rsplit("/", maxsplit=1)[-1]
pkg_path = CIBW_CACHE_PATH / "cpython-installer" / python_filename pkg_path = CIBW_CACHE_PATH / "cpython-installer" / python_filename
if not pkg_path.exists(): if not pkg_path.exists():
download(url, pkg_path) download(url, pkg_path)
@@ -217,7 +213,7 @@ def setup_python(
build_frontend: BuildFrontendName, build_frontend: BuildFrontendName,
) -> tuple[Path, dict[str, str]]: ) -> tuple[Path, dict[str, str]]:
uv_path = find_uv() uv_path = find_uv()
use_uv = build_frontend == "build[uv]" use_uv = build_frontend in {"build[uv]", "uv"}
tmp.mkdir() tmp.mkdir()
implementation_id = python_configuration.identifier.split("-")[0] implementation_id = python_configuration.identifier.split("-")[0]
@@ -257,6 +253,10 @@ def setup_python(
# https://github.com/pypa/virtualenv/issues/620 # https://github.com/pypa/virtualenv/issues/620
# Also see https://github.com/python/cpython/pull/9516 # Also see https://github.com/python/cpython/pull/9516
env.pop("__PYVENV_LAUNCHER__", None) env.pop("__PYVENV_LAUNCHER__", None)
# uv uses this over the current environment's python, so remove it to avoid confusion
env.pop("PYTHON_VERSION", None)
env.pop("PYTHON_ARCH", None)
env.pop("UV_PYTHON", None)
# we version pip ourselves, so we don't care about pip version checking # we version pip ourselves, so we don't care about pip version checking
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
@@ -374,12 +374,27 @@ def setup_python(
uv_path, uv_path,
"pip", "pip",
"install", "install",
"--python",
which_python,
"--upgrade", "--upgrade",
"delocate", "delocate",
"build[virtualenv, uv]", "build[virtualenv, uv]",
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
env=env, env=env,
) )
case "uv":
assert uv_path is not None
call(
uv_path,
"pip",
"install",
"--python",
which_python,
"--upgrade",
"delocate",
*constraint_flags(dependency_constraint),
env=env,
)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -412,7 +427,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations: for config in python_configurations:
build_options = options.build_options(config.identifier) build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "build[uv]" use_uv = build_frontend.name in {"build[uv]", "uv"}
uv_path = find_uv() uv_path = find_uv()
if use_uv and uv_path is None: if use_uv and uv_path is None:
msg = "uv not found" msg = "uv not found"
@@ -460,7 +475,10 @@ def build(options: Options, tmp_path: Path) -> None:
built_wheel_dir.mkdir() built_wheel_dir.mkdir()
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend,
build_options.build_verbosity,
build_options.config_settings,
py38=config.identifier[1:].startswith("p38"),
) )
build_env = env.copy() build_env = env.copy()
@@ -497,6 +515,18 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags, *extra_flags,
env=build_env, env=build_env,
) )
case "uv":
assert uv_path is not None
call(
uv_path,
"build",
f"--python={base_python}",
build_options.package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
env=build_env,
)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
+18 -16
View File
@@ -14,16 +14,16 @@ from typing import Final, TypedDict
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import get_build_frontend_extra_flags from cibuildwheel.frontend import get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import ( from cibuildwheel.util.file import (
CIBW_CACHE_PATH, CIBW_CACHE_PATH,
copy_test_sources, copy_test_sources,
download, download,
@@ -31,13 +31,13 @@ from ..util.file import (
extract_zip, extract_zip,
move_file, move_file,
) )
from ..util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs from cibuildwheel.util.helpers import prepare_command, unwrap, unwrap_preserving_paragraphs
from ..util.packaging import find_compatible_wheel, get_pip_version from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
from ..util.python_build_standalone import ( from cibuildwheel.util.python_build_standalone import (
PythonBuildStandaloneError, PythonBuildStandaloneError,
create_python_build_standalone_environment, create_python_build_standalone_environment,
) )
from ..venv import constraint_flags, virtualenv from cibuildwheel.venv import constraint_flags, virtualenv
IS_WIN: Final[bool] = sys.platform.startswith("win") IS_WIN: Final[bool] = sys.platform.startswith("win")
@@ -285,7 +285,6 @@ def setup_python(
"install", "install",
"--upgrade", "--upgrade",
"pyodide-build", "pyodide-build",
"build[virtualenv]",
*constraint_flags(constraints_path), *constraint_flags(constraints_path),
env=env, env=env,
) )
@@ -416,7 +415,10 @@ def build(options: Options, tmp_path: Path) -> None:
log.step("Building wheel...") log.step("Building wheel...")
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend,
build_options.build_verbosity,
build_options.config_settings,
py38=False,
) )
call( call(
+51 -20
View File
@@ -5,26 +5,32 @@ import platform as platform_module
import shutil import shutil
import subprocess import subprocess
import textwrap import textwrap
from collections.abc import MutableMapping, Set from collections.abc import MutableMapping, Sequence, Set
from functools import cache from functools import cache
from pathlib import Path from pathlib import Path
from typing import assert_never from typing import assert_never
from filelock import FileLock from filelock import FileLock
from .. import errors from cibuildwheel import errors
from ..architecture import Architecture from cibuildwheel.architecture import Architecture
from ..environment import ParsedEnvironment from cibuildwheel.environment import ParsedEnvironment
from ..frontend import BuildFrontendName, get_build_frontend_extra_flags from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags
from ..logger import log from cibuildwheel.logger import log
from ..options import Options from cibuildwheel.options import Options
from ..selector import BuildSelector from cibuildwheel.selector import BuildSelector
from ..util import resources from cibuildwheel.util import resources
from ..util.cmd import call, shell from cibuildwheel.util.cmd import call, shell
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file from cibuildwheel.util.file import (
from ..util.helpers import prepare_command, unwrap CIBW_CACHE_PATH,
from ..util.packaging import find_compatible_wheel, get_pip_version copy_test_sources,
from ..venv import constraint_flags, find_uv, virtualenv download,
extract_zip,
move_file,
)
from cibuildwheel.util.helpers import prepare_command, unwrap
from cibuildwheel.util.packaging import find_compatible_wheel, get_pip_version
from cibuildwheel.venv import constraint_flags, find_uv, virtualenv
def get_nuget_args( def get_nuget_args(
@@ -271,7 +277,7 @@ def setup_python(
if build_frontend == "build[uv]" and not can_use_uv(python_configuration): if build_frontend == "build[uv]" and not can_use_uv(python_configuration):
build_frontend = "build" build_frontend = "build"
use_uv = build_frontend == "build[uv]" use_uv = build_frontend in {"build[uv]", "uv"}
uv_path = find_uv() uv_path = find_uv()
log.step("Setting up build environment...") log.step("Setting up build environment...")
@@ -287,7 +293,9 @@ def setup_python(
# set up environment variables for run_with_env # set up environment variables for run_with_env
env["PYTHON_VERSION"] = python_configuration.version env["PYTHON_VERSION"] = python_configuration.version
env["PYTHON_ARCH"] = python_configuration.arch env["PYTHON_ARCH"] = python_configuration.arch
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1" env.pop("UV_PYTHON", None)
if not use_uv:
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
# update env with results from CIBW_ENVIRONMENT # update env with results from CIBW_ENVIRONMENT
env = environment.as_dictionary(prev_environment=env) env = environment.as_dictionary(prev_environment=env)
@@ -328,6 +336,8 @@ def setup_python(
uv_path, uv_path,
"pip", "pip",
"install", "install",
"--python",
where_python,
"--upgrade", "--upgrade",
"build[virtualenv]", "build[virtualenv]",
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
@@ -386,6 +396,8 @@ def build(options: Options, tmp_path: Path) -> None:
if not python_configurations: if not python_configurations:
return return
uv_path = find_uv()
try: try:
before_all_options_identifier = python_configurations[0].identifier before_all_options_identifier = python_configurations[0].identifier
before_all_options = options.build_options(before_all_options_identifier) before_all_options = options.build_options(before_all_options_identifier)
@@ -403,8 +415,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations: for config in python_configurations:
build_options = options.build_options(config.identifier) build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend build_frontend = build_options.build_frontend
use_uv = build_frontend.name in {"build[uv]", "uv"} and can_use_uv(config)
use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
log.build_start(config.identifier) log.build_start(config.identifier)
identifier_tmp_dir = tmp_path / config.identifier identifier_tmp_dir = tmp_path / config.identifier
@@ -449,7 +460,10 @@ def build(options: Options, tmp_path: Path) -> None:
built_wheel_dir.mkdir() built_wheel_dir.mkdir()
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_options.build_verbosity, build_options.config_settings build_frontend,
build_options.build_verbosity,
build_options.config_settings,
py38=config.identifier[1:].startswith("p38"),
) )
if ( if (
@@ -501,6 +515,18 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags, *extra_flags,
env=env, env=env,
) )
case "uv":
assert uv_path is not None
call(
uv_path,
"build",
f"--python={base_python}",
build_options.package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
env=env,
)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -575,7 +601,12 @@ def build(options: Options, tmp_path: Path) -> None:
) )
shell(before_test_prepared, env=virtualenv_env) shell(before_test_prepared, env=virtualenv_env)
pip = ["uv", "pip"] if use_uv else ["pip"] pip: Sequence[Path | str]
if use_uv:
assert uv_path is not None
pip = [uv_path, "pip"]
else:
pip = ["pip"]
# install the wheel # install the wheel
call( call(
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
import os
import shutil
import subprocess
import sys
from pathlib import Path
def main() -> None:
# CIBW_HOST_TRIPLET is set in the android_env to the Android target triplet.
target = os.environ.get("CIBW_HOST_TRIPLET")
cmd_name = Path(sys.argv[0]).name
# Find the real command in PATH, excluding the current script's directory
path_env = os.environ.get("PATH", "")
script_dir = Path(__file__).resolve().parent
paths = path_env.split(os.pathsep)
# Filter out the script directory to avoid recursion
filtered_paths = [p for p in paths if Path(p).resolve() != script_dir]
filtered_path_env = os.pathsep.join(filtered_paths)
real_cmd = shutil.which(cmd_name, path=filtered_path_env)
if not real_cmd:
sys.stderr.write(f"cibuildwheel: Error: Could not find system {cmd_name}\n")
sys.exit(1)
# If we have a target (i.e. we are in the android_env), try to install it.
if target:
# Check if rustup is available to install the target
rustup_path = shutil.which("rustup", path=filtered_path_env)
if rustup_path:
try:
# We call rustup to ensure the target is installed.
subprocess.run(
[rustup_path, "target", "add", target],
check=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
text=True,
)
except subprocess.CalledProcessError as e:
sys.stderr.write(
f"cibuildwheel: Error: Failed to install Rust target {target}: {e.stderr}\n"
)
sys.exit(1)
# Execute the real command
os.execv(real_cmd, [real_cmd, *sys.argv[1:]])
if __name__ == "__main__":
main()
+40 -40
View File
@@ -161,30 +161,30 @@ python_configurations = [
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" }, { identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.9/python-3.13.9-macos11.pkg" }, { identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg" },
{ identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg" }, { identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg" },
{ identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" }, { identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" },
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" }, { identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" }, { identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" }, { identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" }, { identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" }, { identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2" },
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-macos_x86_64.tar.bz2" }, { identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-macos_x86_64.tar.bz2" },
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-macos_arm64.tar.bz2" }, { identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-macos_arm64.tar.bz2" },
{ identifier = "gp311_242-macosx_x86_64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-amd64.tar.gz" }, { identifier = "gp311_242-macosx_x86_64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-amd64.tar.gz" },
{ identifier = "gp311_242-macosx_arm64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-aarch64.tar.gz" }, { identifier = "gp311_242-macosx_arm64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-macos-aarch64.tar.gz" },
{ identifier = "gp312_250-macosx_x86_64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-amd64.tar.gz" }, { identifier = "gp312_250-macosx_x86_64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-amd64.tar.gz" },
{ identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-macos-aarch64.tar.gz" }, { identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.2/graalpy-25.0.2-macos-aarch64.tar.gz" },
] ]
[windows] [windows]
@@ -199,50 +199,50 @@ python_configurations = [
{ identifier = "cp311-win_amd64", version = "3.11.9" }, { identifier = "cp311-win_amd64", version = "3.11.9" },
{ identifier = "cp312-win32", version = "3.12.10" }, { identifier = "cp312-win32", version = "3.12.10" },
{ identifier = "cp312-win_amd64", version = "3.12.10" }, { identifier = "cp312-win_amd64", version = "3.12.10" },
{ identifier = "cp313-win32", version = "3.13.9" }, { identifier = "cp313-win32", version = "3.13.12" },
{ identifier = "cp313t-win32", version = "3.13.9" }, { identifier = "cp313t-win32", version = "3.13.12" },
{ identifier = "cp313-win_amd64", version = "3.13.9" }, { identifier = "cp313-win_amd64", version = "3.13.12" },
{ identifier = "cp313t-win_amd64", version = "3.13.9" }, { identifier = "cp313t-win_amd64", version = "3.13.12" },
{ identifier = "cp314-win32", version = "3.14.0" }, { identifier = "cp314-win32", version = "3.14.3" },
{ identifier = "cp314t-win32", version = "3.14.0" }, { identifier = "cp314t-win32", version = "3.14.3" },
{ identifier = "cp314-win_amd64", version = "3.14.0" }, { identifier = "cp314-win_amd64", version = "3.14.3" },
{ identifier = "cp314t-win_amd64", version = "3.14.0" }, { identifier = "cp314t-win_amd64", version = "3.14.3" },
{ identifier = "cp39-win_arm64", version = "3.9.10" }, { identifier = "cp39-win_arm64", version = "3.9.10" },
{ identifier = "cp310-win_arm64", version = "3.10.11" }, { identifier = "cp310-win_arm64", version = "3.10.11" },
{ identifier = "cp311-win_arm64", version = "3.11.9" }, { identifier = "cp311-win_arm64", version = "3.11.9" },
{ identifier = "cp312-win_arm64", version = "3.12.10" }, { identifier = "cp312-win_arm64", version = "3.12.10" },
{ identifier = "cp313-win_arm64", version = "3.13.9" }, { identifier = "cp313-win_arm64", version = "3.13.12" },
{ identifier = "cp313t-win_arm64", version = "3.13.9" }, { identifier = "cp313t-win_arm64", version = "3.13.12" },
{ identifier = "cp314-win_arm64", version = "3.14.0" }, { identifier = "cp314-win_arm64", version = "3.14.3" },
{ identifier = "cp314t-win_arm64", version = "3.14.0" }, { identifier = "cp314t-win_arm64", version = "3.14.3" },
{ identifier = "pp38-win_amd64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" }, { identifier = "pp38-win_amd64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" },
{ identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" }, { identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
{ identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" }, { identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip" },
{ identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.20-win64.zip" }, { identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.21-win64.zip" },
{ identifier = "gp311_242-win_amd64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-windows-amd64.zip" }, { identifier = "gp311_242-win_amd64", version = "3.11", url = "https://github.com/oracle/graalpython/releases/download/graal-24.2.2/graalpy-24.2.2-windows-amd64.zip" },
{ identifier = "gp312_250-win_amd64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.1/graalpy-25.0.1-windows-amd64.zip" }, { identifier = "gp312_250-win_amd64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.2/graalpy-25.0.2-windows-amd64.zip" },
] ]
[pyodide] [pyodide]
python_configurations = [ python_configurations = [
{ identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22" }, { identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22" },
{ identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.0", node_version = "v22" }, { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.3", node_version = "v22" },
] ]
[android] [android]
python_configurations = [ python_configurations = [
{ identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.8/python-3.13.8-aarch64-linux-android.tar.gz" }, { identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.12/python-3.13.12-aarch64-linux-android.tar.gz" },
{ identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.8/python-3.13.8-x86_64-linux-android.tar.gz" }, { identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.12/python-3.13.12-x86_64-linux-android.tar.gz" },
{ identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-aarch64-linux-android.tar.gz" }, { identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-aarch64-linux-android.tar.gz" },
{ identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.0/python-3.14.0-x86_64-linux-android.tar.gz" }, { identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.3/python-3.14.3-x86_64-linux-android.tar.gz" },
] ]
[ios] [ios]
python_configurations = [ python_configurations = [
{ identifier = "cp313-ios_arm64_iphoneos", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" }, { identifier = "cp313-ios_arm64_iphoneos", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b13/Python-3.13-iOS-support.b13.tar.gz" },
{ identifier = "cp313-ios_x86_64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" }, { identifier = "cp313-ios_x86_64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b13/Python-3.13-iOS-support.b13.tar.gz" },
{ identifier = "cp313-ios_arm64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b12/Python-3.13-iOS-support.b12.tar.gz" }, { identifier = "cp313-ios_arm64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b13/Python-3.13-iOS-support.b13.tar.gz" },
{ identifier = "cp314-ios_arm64_iphoneos", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" }, { identifier = "cp314-ios_arm64_iphoneos", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b9/Python-3.14-iOS-support.b9.tar.gz" },
{ identifier = "cp314-ios_x86_64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" }, { identifier = "cp314-ios_x86_64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b9/Python-3.14-iOS-support.b9.tar.gz" },
{ identifier = "cp314-ios_arm64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b8/Python-3.14-iOS-support.b8.tar.gz" }, { identifier = "cp314-ios_arm64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b9/Python-3.14-iOS-support.b9.tar.gz" },
] ]
@@ -13,7 +13,6 @@
}, },
"enable": { "enable": {
"enum": [ "enum": [
"cpython-experimental-riscv64",
"cpython-freethreading", "cpython-freethreading",
"cpython-prerelease", "cpython-prerelease",
"graalpy", "graalpy",
@@ -108,13 +107,14 @@
}, },
"build-frontend": { "build-frontend": {
"default": "default", "default": "default",
"description": "Set the tool to use to build, either \"build\" (default), \"build[uv]\", or \"pip\"", "description": "Set the tool to use to build, either \"build\" (default), \"build[uv]\", \"uv\", or \"pip\"",
"oneOf": [ "oneOf": [
{ {
"enum": [ "enum": [
"pip", "pip",
"build", "build",
"build[uv]", "build[uv]",
"uv",
"default" "default"
] ]
}, },
@@ -130,6 +130,10 @@
"type": "string", "type": "string",
"pattern": "^build\\[uv\\]; ?args:" "pattern": "^build\\[uv\\]; ?args:"
}, },
{
"type": "string",
"pattern": "^uv; ?args:"
},
{ {
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
@@ -141,7 +145,8 @@
"enum": [ "enum": [
"pip", "pip",
"build", "build",
"build[uv]" "build[uv]",
"uv"
] ]
}, },
"args": { "args": {
@@ -2,59 +2,49 @@
# nox -s update_constraints # nox -s update_constraints
annotated-types==0.7.0 annotated-types==0.7.0
# via pydantic # via pydantic
anyio==4.11.0 auditwheel-emscripten==0.2.3
# via httpx
auditwheel-emscripten==0.2.0
# via pyodide-build # via pyodide-build
build==1.2.2.post1 build==1.2.2.post1
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2025.10.5 certifi==2026.2.25
# via # via requests
# httpcore charset-normalizer==3.4.6
# httpx
# requests
charset-normalizer==3.4.4
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# typer # pyodide-build
# pyodide-cli
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv
h11==0.16.0
# via httpcore
httpcore==1.0.9
# via httpx
httpx==0.28.1
# via unearth
idna==3.11
# via # via
# anyio # python-discovery
# httpx # virtualenv
# requests idna==3.11
leb128==1.0.8 # via requests
leb128==1.0.9
# via auditwheel-emscripten # via auditwheel-emscripten
markdown-it-py==4.0.0 markdown-it-py==4.0.0
# via rich # via rich
mdurl==0.1.2 mdurl==0.1.2
# via markdown-it-py # via markdown-it-py
packaging==25.0 packaging==26.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# build # build
# pyodide-build # pyodide-build
# unearth # wheel
pip==25.3 pip==26.0.1
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.5.0 platformdirs==4.9.4
# via # via
# pyodide-build # pyodide-build
# python-discovery
# virtualenv # virtualenv
pydantic==2.12.4 pydantic==2.12.5
# via # via
# pyodide-build # pyodide-build
# pyodide-lock # pyodide-lock
@@ -62,56 +52,40 @@ pydantic-core==2.41.5
# via pydantic # via pydantic
pygments==2.19.2 pygments==2.19.2
# via rich # via rich
pyodide-build==0.30.8 pyodide-build==0.33.0
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.4.0 pyodide-cli==0.5.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
pyodide-lock==0.1.0 pyodide-lock==0.1.2
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
resolvelib==1.2.1 rich==14.3.3
# via pyodide-build
rich==14.2.0
# via # via
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
# typer ruamel-yaml==0.19.1
ruamel-yaml==0.18.16
# via pyodide-build # via pyodide-build
ruamel-yaml-clib==0.2.14
# via ruamel-yaml
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via anyio
typer==0.20.0
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
typing-extensions==4.15.0 typing-extensions==4.15.0
# via # via
# anyio
# pydantic # pydantic
# pydantic-core # pydantic-core
# typer
# typing-inspection # typing-inspection
typing-inspection==0.4.2 typing-inspection==0.4.2
# via pydantic # via pydantic
unearth==0.18.1 urllib3==2.6.3
# via pyodide-build
urllib3==2.5.0
# via requests # via requests
virtualenv==20.35.4 virtualenv==21.2.0
# via # via
# build # build
# pyodide-build # pyodide-build
wheel==0.45.1 wheel==0.46.3
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
@@ -2,59 +2,49 @@
# nox -s update_constraints # nox -s update_constraints
annotated-types==0.7.0 annotated-types==0.7.0
# via pydantic # via pydantic
anyio==4.11.0 auditwheel-emscripten==0.2.3
# via httpx
auditwheel-emscripten==0.2.0
# via pyodide-build # via pyodide-build
build==1.2.2.post1 build==1.2.2.post1
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2025.10.5 certifi==2026.2.25
# via # via requests
# httpcore charset-normalizer==3.4.6
# httpx
# requests
charset-normalizer==3.4.4
# via requests # via requests
click==8.1.8 click==8.1.8
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# typer # pyodide-build
# pyodide-cli
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv
h11==0.16.0
# via httpcore
httpcore==1.0.9
# via httpx
httpx==0.28.1
# via unearth
idna==3.11
# via # via
# anyio # python-discovery
# httpx # virtualenv
# requests idna==3.11
leb128==1.0.8 # via requests
leb128==1.0.9
# via auditwheel-emscripten # via auditwheel-emscripten
markdown-it-py==4.0.0 markdown-it-py==4.0.0
# via rich # via rich
mdurl==0.1.2 mdurl==0.1.2
# via markdown-it-py # via markdown-it-py
packaging==25.0 packaging==26.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# build # build
# pyodide-build # pyodide-build
# unearth # wheel
pip==25.3 pip==26.0.1
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.5.0 platformdirs==4.9.4
# via # via
# pyodide-build # pyodide-build
# python-discovery
# virtualenv # virtualenv
pydantic==2.12.4 pydantic==2.12.5
# via # via
# pyodide-build # pyodide-build
# pyodide-lock # pyodide-lock
@@ -62,55 +52,40 @@ pydantic-core==2.41.5
# via pydantic # via pydantic
pygments==2.19.2 pygments==2.19.2
# via rich # via rich
pyodide-build==0.30.8 pyodide-build==0.33.0
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.4.0 pyodide-cli==0.5.0
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
pyodide-lock==0.1.0 pyodide-lock==0.1.2
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
requests==2.32.5 requests==2.32.5
# via pyodide-build # via pyodide-build
resolvelib==1.2.1 rich==14.3.3
# via pyodide-build
rich==14.2.0
# via # via
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
# typer ruamel-yaml==0.19.1
ruamel-yaml==0.18.16
# via pyodide-build # via pyodide-build
ruamel-yaml-clib==0.2.14
# via ruamel-yaml
shellingham==1.5.4
# via typer
sniffio==1.3.1
# via anyio
typer==0.20.0
# via
# auditwheel-emscripten
# pyodide-build
# pyodide-cli
typing-extensions==4.15.0 typing-extensions==4.15.0
# via # via
# pydantic # pydantic
# pydantic-core # pydantic-core
# typer
# typing-inspection # typing-inspection
typing-inspection==0.4.2 typing-inspection==0.4.2
# via pydantic # via pydantic
unearth==0.18.1 urllib3==2.6.3
# via pyodide-build
urllib3==2.5.0
# via requests # via requests
virtualenv==20.35.4 virtualenv==21.2.0
# via # via
# build # build
# pyodide-build # pyodide-build
wheel==0.45.1 wheel==0.46.3
# via # via
# auditwheel-emscripten # auditwheel-emscripten
# pyodide-build # pyodide-build
@@ -1,36 +1,42 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
importlib-metadata==8.7.0 # python-discovery
# virtualenv
importlib-metadata==9.0.0
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
tomli==2.3.0 python-discovery==1.2.0
# via virtualenv
tomli==2.4.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.23.0 zipp==3.23.0
# via importlib-metadata # via importlib-metadata
@@ -1,28 +1,34 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
macholib==1.16.3 # python-discovery
# virtualenv
macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,34 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
macholib==1.16.3 # python-discovery
# virtualenv
macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,34 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
macholib==1.16.3 # python-discovery
# virtualenv
macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,28 +1,34 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
macholib==1.16.3 # python-discovery
# virtualenv
macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -1,6 +1,6 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.2.2.post1 build==1.2.2.post1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -9,28 +9,34 @@ delocate==0.12.0
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.16.1 filelock==3.16.1
# via virtualenv # via
# python-discovery
# virtualenv
importlib-metadata==8.5.0 importlib-metadata==8.5.0
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.0.1 pip==25.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.3.6 platformdirs==4.3.6
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
tomli==2.3.0 python-discovery==1.2.0
# via virtualenv
tomli==2.4.0
# via build # via build
typing-extensions==4.13.2 typing-extensions==4.13.2
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.20.2 zipp==3.20.2
# via importlib-metadata # via importlib-metadata
+16 -10
View File
@@ -1,36 +1,42 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.19.1 filelock==3.19.1
# via virtualenv # via
importlib-metadata==8.7.0 # python-discovery
# virtualenv
importlib-metadata==8.7.1
# via build # via build
macholib==1.16.3 macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.4.0 platformdirs==4.4.0
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
tomli==2.3.0 python-discovery==1.2.0
# via virtualenv
tomli==2.4.0
# via build # via build
typing-extensions==4.15.0 typing-extensions==4.15.0
# via # via
# delocate # delocate
# virtualenv # virtualenv
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.23.0 zipp==3.23.0
# via importlib-metadata # via importlib-metadata
+16 -10
View File
@@ -1,28 +1,34 @@
# This file was autogenerated by uv via the following command: # This file was autogenerated by uv via the following command:
# nox -s update_constraints # nox -s update_constraints
altgraph==0.17.4 altgraph==0.17.5
# via macholib # via macholib
build==1.3.0 build==1.4.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.0 distlib==0.4.0
# via virtualenv # via virtualenv
filelock==3.20.0 filelock==3.25.2
# via virtualenv # via
macholib==1.16.3 # python-discovery
# virtualenv
macholib==1.16.4
# via delocate # via delocate
packaging==25.0 packaging==26.0
# via # via
# build # build
# delocate # delocate
pip==25.3 pip==26.0.1
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.5.0 platformdirs==4.9.4
# via virtualenv # via
# python-discovery
# virtualenv
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.2.0
# via virtualenv
typing-extensions==4.15.0 typing-extensions==4.15.0
# via delocate # via delocate
virtualenv==20.35.4 virtualenv==21.2.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
+3 -3
View File
@@ -1,4 +1,4 @@
url = "https://nodejs.org/dist/" url = "https://nodejs.org/dist/"
v24 = "v24.11.0" v24 = "v24.14.0"
v22 = "v22.21.1" v22 = "v22.22.1"
v20 = "v20.19.5" v20 = "v20.20.1"
+34 -34
View File
@@ -1,54 +1,54 @@
[x86_64] [x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.03.20-1
[i686] [i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.03.20-1
[aarch64] [aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.03.20-1
[ppc64le] [ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.03.20-1
[s390x] [s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.03.20-1
[pypy_x86_64] [pypy_x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.03.20-1
[pypy_i686] [pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.03.20-1
[pypy_aarch64] [pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2025.11.09-2 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.03.20-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2025.11.09-2 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.03.20-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2025.11.09-2 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.03.20-1
[armv7l] [armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2025.11.09-2 manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.03.20-1
manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2025.11.09-2 manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.03.20-1
[riscv64] [riscv64]
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2025.11.09-2 manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.03.20-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2025.11.09-2 musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.03.20-1
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
default = { version = "20.35.4", url = "https://github.com/pypa/get-virtualenv/releases/download/20.35.4/virtualenv.pyz" } default = { version = "21.2.0", url = "https://github.com/pypa/get-virtualenv/releases/download/21.2.0/virtualenv.pyz" }
+1 -1
View File
@@ -1,7 +1,7 @@
import json import json
from typing import Any from typing import Any
from .util import resources from cibuildwheel.util import resources
def get_schema(tool_name: str = "cibuildwheel") -> dict[str, Any]: def get_schema(tool_name: str = "cibuildwheel") -> dict[str, Any]:
+8 -8
View File
@@ -2,7 +2,7 @@ import dataclasses
import itertools import itertools
from enum import StrEnum from enum import StrEnum
from fnmatch import fnmatch from fnmatch import fnmatch
from typing import Any from typing import Self
import bracex import bracex
from packaging.specifiers import SpecifierSet from packaging.specifiers import SpecifierSet
@@ -29,7 +29,6 @@ class EnableGroup(StrEnum):
Groups of build selectors that are not enabled by default. Groups of build selectors that are not enabled by default.
""" """
CPythonExperimentalRiscV64 = "cpython-experimental-riscv64"
CPythonFreeThreading = "cpython-freethreading" CPythonFreeThreading = "cpython-freethreading"
CPythonPrerelease = "cpython-prerelease" CPythonPrerelease = "cpython-prerelease"
GraalPy = "graalpy" GraalPy = "graalpy"
@@ -38,11 +37,12 @@ class EnableGroup(StrEnum):
PyodidePrerelease = "pyodide-prerelease" PyodidePrerelease = "pyodide-prerelease"
@classmethod @classmethod
def all_groups(cls) -> frozenset["EnableGroup"]: def all_groups(cls) -> frozenset[Self]:
return frozenset(set(cls) - {cls.CPythonExperimentalRiscV64}) # see https://github.com/python/mypy/issues/20434 for the reason to type: ignore[arg-type]
return frozenset(set(cls) - {cls.CPythonFreeThreading}) # type: ignore[arg-type]
@classmethod @classmethod
def parse_option_value(cls, value: str) -> frozenset["EnableGroup"]: def parse_option_value(cls, value: str) -> frozenset[Self]:
""" """
Parses a string of space-separated values into a set of EnableGroup Parses a string of space-separated values into a set of EnableGroup
members. The string may contain group names or "all". members. The string may contain group names or "all".
@@ -76,7 +76,7 @@ class BuildSelector:
def __call__(self, build_id: str) -> bool: def __call__(self, build_id: str) -> bool:
# Filter build selectors by python_requires if set # Filter build selectors by python_requires if set
if self.requires_python is not None: if self.requires_python is not None:
py_ver_str = build_id.split("-")[0].split("_")[0] py_ver_str = build_id.split("-", maxsplit=1)[0].split("_", maxsplit=1)[0]
py_ver_str = py_ver_str.removesuffix("t") py_ver_str = py_ver_str.removesuffix("t")
major = int(py_ver_str[2]) major = int(py_ver_str[2])
minor = int(py_ver_str[3:]) minor = int(py_ver_str[3:])
@@ -114,7 +114,7 @@ class BuildSelector:
return should_build and not should_skip return should_build and not should_skip
def options_summary(self) -> Any: def options_summary(self) -> dict[str, str | list[str]]:
return { return {
"build_config": self.build_config, "build_config": self.build_config,
"skip_config": self.skip_config, "skip_config": self.skip_config,
@@ -135,5 +135,5 @@ class TestSelector:
should_skip = selector_matches(self.skip_config, build_id) should_skip = selector_matches(self.skip_config, build_id)
return not should_skip return not should_skip
def options_summary(self) -> Any: def options_summary(self) -> dict[str, str]:
return {"skip_config": self.skip_config} return {"skip_config": self.skip_config}
+2 -2
View File
@@ -7,8 +7,8 @@ import typing
from collections.abc import Iterator, Mapping from collections.abc import Iterator, Mapping
from typing import Final, Literal from typing import Final, Literal
from ..errors import FatalError from cibuildwheel.errors import FatalError
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
_IS_WIN: Final[bool] = sys.platform.startswith("win") _IS_WIN: Final[bool] = sys.platform.startswith("win")
+1 -1
View File
@@ -12,7 +12,7 @@ from zipfile import ZipFile
import certifi import certifi
from platformdirs import user_cache_path from platformdirs import user_cache_path
from ..errors import FatalError from cibuildwheel.errors import FatalError
DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa") DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa")
CIBW_CACHE_PATH: Final[Path] = Path( CIBW_CACHE_PATH: Final[Path] = Path(
+1 -1
View File
@@ -7,7 +7,7 @@ import textwrap
from collections import defaultdict from collections import defaultdict
from collections.abc import Sequence from collections.abc import Sequence
from ..typing import PathOrStr from cibuildwheel.typing import PathOrStr
def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str: def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str:
+8 -9
View File
@@ -2,13 +2,13 @@ import shlex
from collections.abc import Mapping, Sequence from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path, PurePath from pathlib import Path, PurePath
from typing import Any, Literal, Self, TypeVar from typing import Literal, Self, TypeVar
from packaging.utils import parse_wheel_filename from packaging.utils import parse_wheel_filename
from . import resources from cibuildwheel.util import resources
from .cmd import call from cibuildwheel.util.cmd import call
from .helpers import parse_key_value_string, unwrap from cibuildwheel.util.helpers import parse_key_value_string, unwrap
@dataclass(kw_only=True) @dataclass(kw_only=True)
@@ -102,7 +102,7 @@ class DependencyConstraints:
return None return None
def options_summary(self) -> Any: def options_summary(self) -> str | dict[str, str]:
if self == DependencyConstraints.pinned(): if self == DependencyConstraints.pinned():
return "pinned" return "pinned"
elif self.packages: elif self.packages:
@@ -169,10 +169,9 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
elif platform.startswith("pyodide"): elif platform.startswith("pyodide"):
# each Pyodide version has its own platform tag # each Pyodide version has its own platform tag
continue continue
else: # Windows should exactly match
# Windows should exactly match elif tag.platform != platform:
if tag.platform != platform: continue
continue
# If all the filters above pass, then the wheel is a previously built compatible wheel. # If all the filters above pass, then the wheel is a previously built compatible wheel.
return wheel return wheel
+1 -1
View File
@@ -3,7 +3,7 @@ import tomllib
from pathlib import Path from pathlib import Path
from typing import Final from typing import Final
from ..typing import PlatformName from cibuildwheel.typing import PlatformName
PATH: Final[Path] = Path(__file__).parent.parent / "resources" PATH: Final[Path] = Path(__file__).parent.parent / "resources"
INSTALL_CERTIFI_SCRIPT: Final[Path] = PATH / "install_certifi.py" INSTALL_CERTIFI_SCRIPT: Final[Path] = PATH / "install_certifi.py"
+6 -4
View File
@@ -12,9 +12,9 @@ from filelock import FileLock
from packaging.requirements import InvalidRequirement, Requirement from packaging.requirements import InvalidRequirement, Requirement
from packaging.version import Version from packaging.version import Version
from .util import resources from cibuildwheel.util import resources
from .util.cmd import call from cibuildwheel.util.cmd import call
from .util.file import CIBW_CACHE_PATH, download from cibuildwheel.util.file import CIBW_CACHE_PATH, download
_IS_WIN: Final[bool] = sys.platform.startswith("win") _IS_WIN: Final[bool] = sys.platform.startswith("win")
@@ -108,7 +108,9 @@ def virtualenv(
assert python.exists() assert python.exists()
if use_uv: if use_uv:
call("uv", "venv", venv_path, "--python", python) uv_path = find_uv()
assert uv_path is not None
call(uv_path, "venv", venv_path, "--python", python)
else: else:
virtualenv_app, virtualenv_version = _ensure_virtualenv(version) virtualenv_app, virtualenv_version = _ensure_virtualenv(version)
if pip_version is None: if pip_version is None:
+33
View File
@@ -4,6 +4,33 @@ title: Changelog
# Changelog # Changelog
### v3.4.1
_2 April 2026_
- ⚠️ Building for the experimental CPython 3.13 free-threading variant is now deprecated. That functionality will be removed in the next minor release. The [`enable`](https://cibuildwheel.pypa.io/en/stable/options/#enable) option `cpython-freethreading` is therefore also deprecated. Builds specifying `enable = "all"` no longer select `cpython-freethreading`. CPython 3.14 free-threading support remains available without the `enable` flag. (#2787)
- 🐛 iOS builds will no longer skip `repair-wheel-command` if it's defined in config (#2761)
- 🐛 Fix bug causing `uv` to fail when environments define PYTHON_VERSION or UV_PYTHON, conflicting with our venvs (#2795)
- ✨ cibuildwheel prints the selected build identifiers at the start of the build. (#2785)
- 🔐 The GitHub Action now references other actions with a full SHA (#2744)
### v3.4.0
_5 March 2026_
- 🌟 You can now build wheels using `uv` as a build frontend. This should improve performance, especially if your project has lots of build dependencies. To use, set [`build-frontend`](https://cibuildwheel.pypa.io/en/stable/options/#build-frontend) to `uv`. (#2322)
- ⚠️ We no longer support running on Travis CI. It may continue working but we don't run tests there anymore so we can't be sure. (#2682)
- ✨ Improvements to building rust wheels on Android (#2650)
- 🐛 Fix bug with the GitHub Action on Windows, where PATH was getting unnecessarily changed, causing issues with meson builds. (#2723)
- ✨ Add support for quiet setting on `build` and `uv` from the cibuildwheel `build-verbosity` setting. (#2737)
- 📚 Docs updates, including guidance on using Meson on Windows (#2718)
### v3.3.1
_5 January 2026_
- 🛠 Update dependencies and container pins, including updating to CPython 3.14.2. (#2708)
### v3.3.0 ### v3.3.0
_12 November 2025_ _12 November 2025_
@@ -150,6 +177,12 @@ See @henryiii's [release post](https://iscinumpy.dev/post/cibuildwheel-3-0-0/) f
- 📚 Docs now primarily use the pyproject.toml name of options, rather than the environment variable name. (#2389) - 📚 Docs now primarily use the pyproject.toml name of options, rather than the environment variable name. (#2389)
- 📚 README table now matches docs and auto-updates. (#2427, #2428) - 📚 README table now matches docs and auto-updates. (#2427, #2428)
### v2.23.4
_16 March 2026_
- 🐛 Fix HTTP 429 errors while downloading virtualenv from GitHub blob URLs uses a https://bootstrap.pypa.io/ URL instead. (#2775)
### v2.23.3 ### v2.23.3
_26 April 2025_ _26 April 2025_
-16
View File
@@ -72,22 +72,6 @@ Commit this file, enable building of your repo on Azure Pipelines, and push.
Wheels will be stored for you and available through the Pipelines interface. For more info on this file, check out the [docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema). Wheels will be stored for you and available through the Pipelines interface. For more info on this file, check out the [docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema).
### Travis CI [linux/windows] {: #travis-ci}
To build Linux and Windows wheels on Travis CI, create a `.travis.yml` file in your repo.
> .travis.yml
```yaml
{% include "../examples/travis-ci-minimal.yml" %}
```
Commit this file, enable building of your repo on Travis CI, and push.
Then setup a deployment method by following the [Travis CI deployment docs](https://docs.travis-ci.com/user/deployment/), or see [Delivering to PyPI](deliver-to-pypi.md). For more info on `.travis.yml`, check out the [docs](https://docs.travis-ci.com/).
[`examples/travis-ci-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/travis-ci-deploy.yml) extends this minimal example with a demonstration of how to automatically upload the built wheels to PyPI.
### CircleCI [linux/mac] {: #circleci} ### CircleCI [linux/mac] {: #circleci}
To build Linux and Mac wheels on CircleCI, create a `.circleci/config.yml` file in your repo, To build Linux and Mac wheels on CircleCI, create a `.circleci/config.yml` file in your repo,
-11
View File
@@ -30,17 +30,6 @@ cibuildwheel to run tests, add the following YAML to your CI config file:
CIBW_TEST_COMMAND: "pytest {project}/tests" CIBW_TEST_COMMAND: "pytest {project}/tests"
``` ```
!!! tab "Travis CI"
> .travis.yml ([docs](https://docs.travis-ci.com/user/environment-variables/))
```yaml
env:
global:
- CIBW_TEST_REQUIRES=pytest
- CIBW_TEST_COMMAND="pytest {project}/tests"
```
!!! tab "CircleCI" !!! tab "CircleCI"
> .circleci/config.yml ([docs](https://circleci.com/docs/2.0/configuration-reference/#environment)) > .circleci/config.yml ([docs](https://circleci.com/docs/2.0/configuration-reference/#environment))
+2 -7
View File
@@ -29,10 +29,11 @@ GitHub actions has pipx in all the runners as a supported package manager, as we
name: Make SDist name: Make SDist
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with: with:
fetch-depth: 0 # Optional, use if you use setuptools_scm fetch-depth: 0 # Optional, use if you use setuptools_scm
submodules: true # Optional, use if you have submodules submodules: true # Optional, use if you have submodules
persist-credentials: false # Highly recommended as a good security practice to not store credentials in disk, unless you need this for your specific use case
- name: Build SDist - name: Build SDist
run: pipx run build --sdist run: pipx run build --sdist
@@ -71,12 +72,6 @@ for an example configuration that automatically uploads wheels to PyPI. Also see
[scikit-hep.org/developer/gha_wheels](https://scikit-hep.org/developer/gha_wheels) [scikit-hep.org/developer/gha_wheels](https://scikit-hep.org/developer/gha_wheels)
for a complete guide. for a complete guide.
### TravisCI
See
[`examples/travis-ci-deploy.yml`](https://github.com/pypa/cibuildwheel/blob/main/examples/travis-ci-deploy.yml)
for an example configuration.
## Manual method ## Manual method
On your development machine, install [pipx](https://pipx.pypa.io/) and do the following: On your development machine, install [pipx](https://pipx.pypa.io/) and do the following:
+21 -3
View File
@@ -99,6 +99,21 @@ Second, there might be platforms you want to ship for that NumPy (or some other
(Note the `*_ONLY_BINARY` variable also supports `":all:"`, and you don't need both that and `*_PREFER_BINARY`, you can use either one, depending on if you want a missing wheel to be a failure or an attempt to build in CI.) (Note the `*_ONLY_BINARY` variable also supports `":all:"`, and you don't need both that and `*_PREFER_BINARY`, you can use either one, depending on if you want a missing wheel to be a failure or an attempt to build in CI.)
### Building with Meson-Python on Windows
Meson generally works well with cibuildwheel, but there are a few things to be aware of:
- On GitHub Actions, the compiler that's chosen by default on Windows is often the MinGW compiler, rather than the MSVC toolchain that Python was compiled with.
The simplest fix for this is to configure cibuildwheel to pass the `--vsenv` flag to meson, like this:
```toml
[tool.cibuildwheel.windows]
config-settings = { "setup-args" = "--vsenv" }
```
- If you need to build 32-bit Windows wheels, you need to activate a 32-bit compiler toolchain before starting cibuildwheel. Many users use [ilammy/msvc-dev-cmd](https://github.com/ilammy/msvc-dev-cmd) for this purpose.
### Automatic updates using Dependabot {: #automatic-updates} ### Automatic updates using Dependabot {: #automatic-updates}
Selecting a moving target (like the latest release) is generally a bad idea in CI. If something breaks, you can't tell whether it was your code or an upstream update that caused the breakage, and in a worst-case scenario, it could occur during a release. Selecting a moving target (like the latest release) is generally a bad idea in CI. If something breaks, you can't tell whether it was your code or an upstream update that caused the breakage, and in a worst-case scenario, it could occur during a release.
@@ -110,11 +125,14 @@ There are two suggested methods for keeping cibuildwheel up to date that instead
If you use GitHub Actions for builds, you can use cibuildwheel as an action: If you use GitHub Actions for builds, you can use cibuildwheel as an action:
```yaml ```yaml
uses: pypa/cibuildwheel@v3.3.0 uses: pypa/cibuildwheel@v3.4.1
``` ```
This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal. This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal.
!!! note "Minor version tags"
Unlike some GitHub Actions, cibuildwheel does **not** provide a floating `@v3` major-version tag, since our minor version change can add/remove wheels. You can, however, pin to a minor version such as `@v3.4` to automatically receive patch releases within that minor version. Dependabot (shown below) is the recommended way to stay up to date.
Then, your `.github/dependabot.yml` file could look like this: Then, your `.github/dependabot.yml` file could look like this:
```yaml ```yaml
@@ -132,7 +150,7 @@ The second option, and the only one that supports other CI systems, is using a `
```bash ```bash
# requirements-cibw.txt # requirements-cibw.txt
cibuildwheel==3.3.0 cibuildwheel==3.4.1
``` ```
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this: Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this:
@@ -297,7 +315,7 @@ Solutions to this vary, but the simplest is to use pipx:
# most runners have pipx preinstalled, but in case you don't # most runners have pipx preinstalled, but in case you don't
python3 -m pip install pipx python3 -m pip install pipx
pipx run cibuildwheel==3.3.0 --output-dir wheelhouse pipx run cibuildwheel==3.4.1 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl pipx run twine upload wheelhouse/*.whl
``` ```
+5
View File
@@ -22,3 +22,8 @@ This diagram summarises the steps that cibuildwheel takes on each platform to bu
%} %}
This isn't exhaustive, for a full list of the things cibuildwheel can do, check the [options](options.md) page. This isn't exhaustive, for a full list of the things cibuildwheel can do, check the [options](options.md) page.
!!! warning "A note on security"
Building and testing wheels executes arbitrary code from your project and its dependencies. Although cibuildwheel uses OCI containers and Pyodide for some builds, these provide no security guarantees - the code you're building and testing has full access to the environment that's invoking cibuildwheel.
If you cannot trust all the code that's pulled in, maintain good security hygiene: keep the job that builds distributions separate from the job that uploads them to PyPI, handle secrets and credentials with care and rotate them regularly, and follow the principle of least privilege when granting permissions. Do not store sensitive data on CI runners.
+2 -2
View File
@@ -8,10 +8,10 @@ import rich.console
import rich.text import rich.text
def define_env(env: Any) -> None: def define_env(env: Any) -> None: # noqa: ANN401
"Hook function for mkdocs-macros" "Hook function for mkdocs-macros"
@env.macro # type: ignore[misc] @env.macro # type: ignore[untyped-decorator]
def subprocess_run(*args: str) -> str: def subprocess_run(*args: str) -> str:
"Run a subprocess and return the stdout" "Run a subprocess and return the stdout"
env = os.environ.copy() env = os.environ.copy()
+33 -18
View File
@@ -465,6 +465,7 @@ Options:
- `build[;args: ...]` - `build[;args: ...]`
- `build[uv][;args: ...]` - `build[uv][;args: ...]`
- `pip[;args: ...]` - `pip[;args: ...]`
- `uv[;args: ...]`
Default: `build` Default: `build`
@@ -477,8 +478,14 @@ Make sure you have an external uv on Windows and macOS, either by
pre-installing it, or installing cibuildwheel with the `uv` extra, which is pre-installing it, or installing cibuildwheel with the `uv` extra, which is
possible by manually passing `cibuildwheel[uv]` to installers or by using the possible by manually passing `cibuildwheel[uv]` to installers or by using the
`extras` option in the [cibuildwheel action](ci-services.md#github-actions). `extras` option in the [cibuildwheel action](ci-services.md#github-actions).
uv currently does not support iOS or musllinux on s390x. Legacy dependencies uv currently does not support iOS or musllinux on s390x, ppc64le and riscv64.
like setuptools on Python < 3.12 and pip are not installed if using uv. You can also use the `uv` backend directly; though currently multiple output
files (from workspaces) are not supported.
!!! note
There is currently a compatibility issue between GraalPy and uv. If you
are building GraalPy wheels, use `build` or `pip` as the build frontend
instead of `build[uv]` or `uv`.
On Android and Pyodide, the "pip" frontend is not supported. On Android and Pyodide, the "pip" frontend is not supported.
@@ -512,6 +519,9 @@ optional `args` option.
# Use uv and build with an argument # Use uv and build with an argument
build-frontend = { name = "build[uv]", args = ["--no-isolation"] } build-frontend = { name = "build[uv]", args = ["--no-isolation"] }
# Use uv directly
build-frontend = "uv"
``` ```
!!! tab examples "Environment variables" !!! tab examples "Environment variables"
@@ -528,6 +538,9 @@ optional `args` option.
# Use uv and build with an argument # Use uv and build with an argument
CIBW_BUILD_FRONTEND: "build[uv]; args: --no-isolation" CIBW_BUILD_FRONTEND: "build[uv]; args: --no-isolation"
# Use uv directly
CIBW_BUILD_FRONTEND: "uv"
``` ```
@@ -621,6 +634,8 @@ Platform-specific environment variables are also available:<br/>
In configuration files, you can use a [TOML][] table instead of a raw string as shown above. In configuration files, you can use a [TOML][] table instead of a raw string as shown above.
[TOML]: https://toml.io/en/
!!! tab examples "Environment variables" !!! tab examples "Environment variables"
```yaml ```yaml
@@ -896,6 +911,10 @@ Default:
- on macOS: `'delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}'` - on macOS: `'delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}'`
- on Android: There is no default command, but cibuildwheel will add `libc++` to the - on Android: There is no default command, but cibuildwheel will add `libc++` to the
wheel if anything links against it. Setting a command will replace this behavior. wheel if anything links against it. Setting a command will replace this behavior.
- on Pyodide: You can use `pyodide auditwheel repair --libdir /path/to/libraries --output-dir {dest_dir} {wheel}` command to repair the wheel.
Unlike other platforms, this command is not set by default as you need to explicitly
specify the library directory. You might not want to use the libraries in the system
directory, as they are not built for WASM and will not work.
- on other platforms: `''` - on other platforms: `''`
A shell command to repair a built wheel by copying external library dependencies into the wheel tree and relinking them. A shell command to repair a built wheel by copying external library dependencies into the wheel tree and relinking them.
@@ -923,12 +942,6 @@ Platform-specific environment variables are also available:<br/>
[Delvewheel]: https://github.com/adang1345/delvewheel [Delvewheel]: https://github.com/adang1345/delvewheel
!!! tip
When using `--platform pyodide`, `pyodide build` is used to do the build,
which already uses `auditwheel-emscripten` to repair the wheel, so the default
repair command is empty. If there is a way to do this in two steps in the future,
this could change.
#### Examples #### Examples
!!! tab examples "pyproject.toml" !!! tab examples "pyproject.toml"
@@ -1242,7 +1255,7 @@ Platform-specific environment variables are also available:<br/>
[tool.cibuildwheel.pyodide] [tool.cibuildwheel.pyodide]
# Choose a specific pyodide-build version # Choose a specific pyodide-build version
dependency-versions = { packages = ["pyodide-build==0.29.1"] } dependency-versions = { packages = ["pyodide-build==0.31.2"] }
``` ```
!!! tab examples "Environment variables" !!! tab examples "Environment variables"
@@ -1261,7 +1274,7 @@ Platform-specific environment variables are also available:<br/>
CIBW_DEPENDENCY_VERSIONS: "packages: auditwheel==6.2.0" CIBW_DEPENDENCY_VERSIONS: "packages: auditwheel==6.2.0"
# Choose a specific pyodide-build version # Choose a specific pyodide-build version
CIBW_DEPENDENCY_VERSIONS_PYODIDE: "packages: pyodide-build==0.29.1" CIBW_DEPENDENCY_VERSIONS_PYODIDE: "packages: pyodide-build==0.31.2"
# Use shell-style quoting around spaces package specifiers # Use shell-style quoting around spaces package specifiers
CIBW_DEPENDENCY_VERSIONS: "packages: 'pip >=16.0.0, !=17'" CIBW_DEPENDENCY_VERSIONS: "packages: 'pip >=16.0.0, !=17'"
@@ -1752,14 +1765,16 @@ will not produce more logging about the build itself. Other levels only affect
the build frontend output, which is usually things like resolving and the build frontend output, which is usually things like resolving and
downloading dependencies. The settings are: downloading dependencies. The settings are:
| | build | pip | desc | | | build | pip | uv | desc |
|-------------|-------|--------|----------------------------------| |-------------|-------|--------|-------|----------------------------------|
| -2 | N/A | `-qq` | even more quiet, where supported | | -2 | `-qq`[^1] | `-qq` | `-qq` | even more quiet, where supported |
| -1 | N/A | `-q` | quiet mode, where supported | | -1 | `-q`[^1] | `-q` | `-q` | quiet mode, where supported |
| 0 (default) | | | default for build tool | | 0 (default) | | | | default for build tool |
| 1 | | `-v` | print backend output | | 1 | | `-v` | | print backend output |
| 2 | `-v` | `-vv` | print log messages e.g. resolving info | | 2 | `-v` | `-vv` | `-v` | print log messages e.g. resolving info |
| 3 | `-vv` | `-vvv` | print even more debug info | | 3 | `-vv` | `-vvv` | `-vv` | print even more debug info |
[^1]: Not supported on Python 3.8, will be ignored with a warning.
Settings that are not supported for a specific frontend will log a warning. Settings that are not supported for a specific frontend will log a warning.
The default build frontend is `build`, which does show build backend output by The default build frontend is `build`, which does show build backend output by
+16 -7
View File
@@ -179,13 +179,24 @@ If there are pre-releases available for a newer Pyodide version, the `pyodide-pr
Currently, it's recommended to run tests using a `python -m` entrypoint, rather than a command line entrypoint, or a shell script. This is because custom entrypoints have some issues in the Pyodide virtual environment. For example, `pytest` may not work as a command line entrypoint, but will work as a `python -m pytest` entrypoint. Currently, it's recommended to run tests using a `python -m` entrypoint, rather than a command line entrypoint, or a shell script. This is because custom entrypoints have some issues in the Pyodide virtual environment. For example, `pytest` may not work as a command line entrypoint, but will work as a `python -m pytest` entrypoint.
### Repairing wheels
Unlike other platforms, cibuildwheel does not set a default [`repair-wheel-command`](options.md#repair-wheel-command) for Pyodide. If your package links shared libraries, you need to explicitly configure the repair command using [`pyodide auditwheel`](https://github.com/pyodide/auditwheel-emscripten):
```toml
[tool.cibuildwheel.pyodide]
repair-wheel-command = "pyodide auditwheel repair --libdir /path/to/libraries --output-dir {dest_dir} {wheel}"
```
The `--libdir` option specifies the directory containing cross-compiled shared libraries for WASM. You should not use the system library directories (e.g. `/usr/lib`), as those libraries are not built for WebAssembly.
## Android {: android} ## Android {: android}
### Prerequisites ### Prerequisites
cibuildwheel can build Android wheels on any POSIX platform supported by the Android cibuildwheel can build Android wheels on any POSIX platform supported by the Android
development tools, which currently means Linux x86_64, macOS ARM64 or macOS x86_64. Any development tools, which currently means Linux `x86_64`, macOS `ARM64` or macOS `x86_64`. Any
of these platforms can be used to build wheels for any Android architecture supported by of these platforms can be used to build wheels for any Android architecture supported by
Python. However, *testing* wheels has additional requirements: see the section below. Python. However, *testing* wheels has additional requirements: see the section below.
@@ -221,10 +232,8 @@ Python 3.13.
### Build frontend support ### Build frontend support
Android builds only support the `build` frontend. In principle, support for the Android builds do not support the `pip` frontend. The `build`, `build[uv]`, and
`build[uv]` frontend should be possible, but `uv` [doesn't currently have support for `uv` frontends work.
cross-platform builds](https://github.com/astral-sh/uv/issues/7957), and [doesn't have
support for iOS or Android wheel tags](https://github.com/astral-sh/uv/issues/8029).
### Tests ### Tests
@@ -238,7 +247,7 @@ Any arguments specified using [`test-runtime`](options.md#test-runtime) will be
Running an emulator requires the build machine to either be bare-metal or support Running an emulator requires the build machine to either be bare-metal or support
nested virtualization. CI platforms known to meet this requirement are: nested virtualization. CI platforms known to meet this requirement are:
* GitHub Actions Linux x86_64 * GitHub Actions Linux `x86_64`
On Linux, the emulator needs access to the KVM virtualization interface. This may On Linux, the emulator needs access to the KVM virtualization interface. This may
require adding your user to a group, or changing your udev rules. On GitHub require adding your user to a group, or changing your udev rules. On GitHub
@@ -308,7 +317,7 @@ iOS builds are *cross platform builds*, as it not possible to run compilers and
### Build frontend support ### Build frontend support
iOS builds support both the `pip` and `build` build frontends. In principle, support for `uv` with the `build[uv]` frontend should be possible, but `uv` [doesn't currently have support for cross-platform builds](https://github.com/astral-sh/uv/issues/7957), and [doesn't have support for iOS (or Android) tags](https://github.com/astral-sh/uv/issues/8029). iOS builds support both the `pip` and `build` build frontends. In principle, support for `uv` and `build[uv]` frontends should be possible, but `uv` [doesn't support iOS fully yet](https://github.com/astral-sh/uv/issues/16724).
### Build environment ### Build environment
+30 -30
View File
@@ -12,9 +12,9 @@ title: Working examples
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system | | [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. | | [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. | | [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform | | [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 | | [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
| [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. |
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. | | [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. | | [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS | | [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
@@ -24,21 +24,21 @@ title: Working examples
| [psutil][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Cross-platform lib for process and system monitoring in Python | | [psutil][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Cross-platform lib for process and system monitoring in Python |
| [Google Benchmark][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A microbenchmark support library | | [Google Benchmark][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A microbenchmark support library |
| [falcon][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Falcon is a no-magic ASGI/WSGI API and microservices framework; it uses cibuildwheel for (optional) Cython extensions. | | [falcon][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Falcon is a no-magic ASGI/WSGI API and microservices framework; it uses cibuildwheel for (optional) Cython extensions. |
| [vaex][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Out-of-Core hybrid Apache Arrow/NumPy DataFrame for Python, ML, visualization and exploration of big tabular data at a billion rows per second 🚀 |
| [PyGame][] | ![github icon][] | ![apple icon][] ![linux icon][] | 🐍🎮 pygame (the library) is a Free and Open Source python programming language library for making multimedia applications like games built on top of the excellent SDL library. C, Python, Native, OpenGL. | | [PyGame][] | ![github icon][] | ![apple icon][] ![linux icon][] | 🐍🎮 pygame (the library) is a Free and Open Source python programming language library for making multimedia applications like games built on top of the excellent SDL library. C, Python, Native, OpenGL. |
| [Apache Beam][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Apache Beam is a unified programming model for Batch and Streaming data processing. | | [Apache Beam][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Apache Beam is a unified programming model for Batch and Streaming data processing. |
| [vaex][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Out-of-Core hybrid Apache Arrow/NumPy DataFrame for Python, ML, visualization and exploration of big tabular data at a billion rows per second 🚀 |
| [asyncpg][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A fast PostgreSQL Database Client Library for Python/asyncio. | | [asyncpg][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A fast PostgreSQL Database Client Library for Python/asyncio. |
| [cmake][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. | | [cmake][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
| [pyinstrument][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python profiler with a C extension. No external dependencies. | | [pyinstrument][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python profiler with a C extension. No external dependencies. |
| [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. | | [scikit-image][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Image processing library. Uses cibuildwheel to build and test a project that uses Cython with platform-native code. |
| [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. | | [cvxpy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A Python-embedded modeling language for convex optimization problems. |
| [PyOxidizer][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool | | [PyOxidizer][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A modern Python application packaging and distribution tool |
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
| [pedalboard][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | A Python library for working with audio data and audio plugins by wrapping the [JUCE](https://github.com/juce-framework/JUCE/) C++ framework. Uses cibuildwheel to deploy on as many operating systems and Python versions as possible with only one dependency (any NumPy). | | [pedalboard][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | A Python library for working with audio data and audio plugins by wrapping the [JUCE](https://github.com/juce-framework/JUCE/) C++ framework. Uses cibuildwheel to deploy on as many operating systems and Python versions as possible with only one dependency (any NumPy). |
| [twisted-iocpsupport][] | ![github icon][] | ![windows icon][] | A submodule of Twisted that hooks into native C APIs using Cython. |
| [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python | | [River][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | 🌊 Online machine learning in Python |
| [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. | | [websockets][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Library for building WebSocket servers and clients. Mostly written in Python, with a small C 'speedups' extension module. |
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
| [OpenSpiel][] | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. | | [OpenSpiel][] | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. |
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
| [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI | | [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI |
| [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings | | [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings |
| [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. | | [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. |
@@ -53,9 +53,9 @@ title: Working examples
| [PyYAML][] | ![github icon][] | ![apple icon][] | Canonical source repository for PyYAML | | [PyYAML][] | ![github icon][] | ![apple icon][] | Canonical source repository for PyYAML |
| [pikepdf][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by QPDF | | [pikepdf][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python library for reading and writing PDF, powered by QPDF |
| [numexpr][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast numerical array expression evaluator for Python, NumPy, Pandas, PyTables and more | | [numexpr][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast numerical array expression evaluator for Python, NumPy, Pandas, PyTables and more |
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. | | [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
| [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. | | [h5py][] | ![azurepipelines icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | HDF5 for Python -- The h5py package is a Pythonic interface to the HDF5 binary data format. |
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool | | [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. | | [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. | | [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
@@ -65,39 +65,39 @@ title: Working examples
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data | | [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data | | [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. | | [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
| [H3-py][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. | | [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) | | [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
| [H3-py][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
| [time-machine][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Time mocking library using only the CPython C API. | | [time-machine][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Time mocking library using only the CPython C API. |
| [mosec][] | ![github icon][] | ![linux icon][] ![apple icon][] | A machine learning model serving framework powered by Rust | | [mosec][] | ![github icon][] | ![linux icon][] ![apple icon][] | A machine learning model serving framework powered by Rust |
| [Picologging][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A high-performance logging library for Python. | | [Picologging][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A high-performance logging library for Python. |
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
| [markupsafe][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. | | [markupsafe][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. |
| [Rtree][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Rtree: spatial index for Python GIS | | [Rtree][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Rtree: spatial index for Python GIS |
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python | | [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
| [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub | | [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub |
| [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. | | [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. |
| [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. | | [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson | | [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
| [abess][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A fast best-subset selection library. It uses cibuildwheel to build a large project with C++ extensions. | | [abess][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A fast best-subset selection library. It uses cibuildwheel to build a large project with C++ extensions. |
| [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library | | [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq | | [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing | | [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
| [matrixprofile][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python 3 library making time series data mining tasks, utilizing matrix profile algorithms, accessible to everyone. | | [matrixprofile][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python 3 library making time series data mining tasks, utilizing matrix profile algorithms, accessible to everyone. |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [Tokenizer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support | | [Tokenizer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast and customizable text tokenization library with BPE and SentencePiece support |
| [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 | | [iminuit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Jupyter-friendly Python interface for C++ MINUIT2 |
| [pillow-heif][] | ![github icon][] ![cirrusci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Bindings to libheif library with third party dependencies. Fully automated CI for tests and publishing including Apple Silicon builds. | | [pillow-heif][] | ![github icon][] ![cirrusci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Bindings to libheif library with third party dependencies. Fully automated CI for tests and publishing including Apple Silicon builds. |
| [keyvi][] | ![github icon][] | ![linux icon][] ![apple icon][] | FST based key value index highly optimized for size and lookup performance, utilizes ccache action for improved runtime | | [keyvi][] | ![github icon][] | ![linux icon][] ![apple icon][] | FST based key value index highly optimized for size and lookup performance, utilizes ccache action for improved runtime |
| [PyGLM][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python | | [PyGLM][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Fast OpenGL Mathematics (GLM) for Python |
| [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 | | [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis | | [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
| [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython | | [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython |
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python | | [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. | | [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. | | [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 | | [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 | | [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
@@ -108,14 +108,14 @@ title: Working examples
| [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. | | [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. | | [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions | | [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. | | [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
| [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. | | [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. | | [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
| [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. | | [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
| [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). | | [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). |
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. | | [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
| [pybind11 cross build example][] | ![github icon][] ![gitlab icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Same as pybind11 cmake_example but used to demo Linux ARM + Windows + macOS builds on GitLab | | [pybind11 cross build example][] | ![github icon][] ![gitlab icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Same as pybind11 cmake_example but used to demo Linux ARM + Windows + macOS builds on GitLab |
@@ -123,9 +123,9 @@ title: Working examples
[duckdb]: https://github.com/duckdb/duckdb [duckdb]: https://github.com/duckdb/duckdb
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq [pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy [NumPy]: https://github.com/numpy/numpy
[Tornado]: https://github.com/tornadoweb/tornado
[NCNN]: https://github.com/Tencent/ncnn [NCNN]: https://github.com/Tencent/ncnn
[Matplotlib]: https://github.com/matplotlib/matplotlib [Matplotlib]: https://github.com/matplotlib/matplotlib
[Tornado]: https://github.com/tornadoweb/tornado
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels [MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
[Prophet]: https://github.com/facebook/prophet [Prophet]: https://github.com/facebook/prophet
[Kivy]: https://github.com/kivy/kivy [Kivy]: https://github.com/kivy/kivy
@@ -135,21 +135,21 @@ title: Working examples
[psutil]: https://github.com/giampaolo/psutil [psutil]: https://github.com/giampaolo/psutil
[Google Benchmark]: https://github.com/google/benchmark [Google Benchmark]: https://github.com/google/benchmark
[falcon]: https://github.com/falconry/falcon [falcon]: https://github.com/falconry/falcon
[vaex]: https://github.com/vaexio/vaex
[PyGame]: https://github.com/pygame/pygame [PyGame]: https://github.com/pygame/pygame
[Apache Beam]: https://github.com/apache/beam [Apache Beam]: https://github.com/apache/beam
[vaex]: https://github.com/vaexio/vaex
[asyncpg]: https://github.com/MagicStack/asyncpg [asyncpg]: https://github.com/MagicStack/asyncpg
[cmake]: https://github.com/scikit-build/cmake-python-distributions [cmake]: https://github.com/scikit-build/cmake-python-distributions
[pyinstrument]: https://github.com/joerick/pyinstrument [pyinstrument]: https://github.com/joerick/pyinstrument
[scikit-image]: https://github.com/scikit-image/scikit-image [scikit-image]: https://github.com/scikit-image/scikit-image
[cvxpy]: https://github.com/cvxpy/cvxpy [cvxpy]: https://github.com/cvxpy/cvxpy
[PyOxidizer]: https://github.com/indygreg/PyOxidizer [PyOxidizer]: https://github.com/indygreg/PyOxidizer
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[pedalboard]: https://github.com/spotify/pedalboard [pedalboard]: https://github.com/spotify/pedalboard
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
[River]: https://github.com/online-ml/river [River]: https://github.com/online-ml/river
[websockets]: https://github.com/python-websockets/websockets [websockets]: https://github.com/python-websockets/websockets
[aiortc]: https://github.com/aiortc/aiortc
[OpenSpiel]: https://github.com/google-deepmind/open_spiel [OpenSpiel]: https://github.com/google-deepmind/open_spiel
[aiortc]: https://github.com/aiortc/aiortc
[Dependency Injector]: https://github.com/ets-labs/python-dependency-injector [Dependency Injector]: https://github.com/ets-labs/python-dependency-injector
[UltraJSON]: https://github.com/ultrajson/ultrajson [UltraJSON]: https://github.com/ultrajson/ultrajson
[CTranslate2]: https://github.com/OpenNMT/CTranslate2 [CTranslate2]: https://github.com/OpenNMT/CTranslate2
@@ -164,9 +164,9 @@ title: Working examples
[PyYAML]: https://github.com/yaml/pyyaml [PyYAML]: https://github.com/yaml/pyyaml
[pikepdf]: https://github.com/pikepdf/pikepdf [pikepdf]: https://github.com/pikepdf/pikepdf
[numexpr]: https://github.com/pydata/numexpr [numexpr]: https://github.com/pydata/numexpr
[Psycopg 3]: https://github.com/psycopg/psycopg
[Wrapt]: https://github.com/GrahamDumpleton/wrapt [Wrapt]: https://github.com/GrahamDumpleton/wrapt
[h5py]: https://github.com/h5py/h5py [h5py]: https://github.com/h5py/h5py
[Psycopg 3]: https://github.com/psycopg/psycopg
[envd]: https://github.com/tensorchord/envd [envd]: https://github.com/tensorchord/envd
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO [OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
[ruptures]: https://github.com/deepcharles/ruptures [ruptures]: https://github.com/deepcharles/ruptures
@@ -176,39 +176,39 @@ title: Working examples
[PyTables]: https://github.com/PyTables/PyTables [PyTables]: https://github.com/PyTables/PyTables
[google neuroglancer]: https://github.com/google/neuroglancer [google neuroglancer]: https://github.com/google/neuroglancer
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth [Parselmouth]: https://github.com/YannickJadoul/Parselmouth
[H3-py]: https://github.com/uber/h3-py
[AutoPy]: https://github.com/autopilot-rs/autopy [AutoPy]: https://github.com/autopilot-rs/autopy
[DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest [DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
[H3-py]: https://github.com/uber/h3-py
[time-machine]: https://github.com/adamchainz/time-machine [time-machine]: https://github.com/adamchainz/time-machine
[mosec]: https://github.com/mosecorg/mosec [mosec]: https://github.com/mosecorg/mosec
[Picologging]: https://github.com/microsoft/picologging [Picologging]: https://github.com/microsoft/picologging
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
[markupsafe]: https://github.com/pallets/markupsafe [markupsafe]: https://github.com/pallets/markupsafe
[Rtree]: https://github.com/Toblerity/rtree [Rtree]: https://github.com/Toblerity/rtree
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
[KDEpy]: https://github.com/tommyod/KDEpy [KDEpy]: https://github.com/tommyod/KDEpy
[dd-trace-py]: https://github.com/DataDog/dd-trace-py [dd-trace-py]: https://github.com/DataDog/dd-trace-py
[tgcalls]: https://github.com/MarshalX/tgcalls [tgcalls]: https://github.com/MarshalX/tgcalls
[sourmash]: https://github.com/sourmash-bio/sourmash [sourmash]: https://github.com/sourmash-bio/sourmash
[pybind11 python_example]: https://github.com/pybind/python_example
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson [python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
[pybind11 python_example]: https://github.com/pybind/python_example
[abess]: https://github.com/abess-team/abess [abess]: https://github.com/abess-team/abess
[python-snappy]: https://github.com/intake/python-snappy [python-snappy]: https://github.com/intake/python-snappy
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[jq.py]: https://github.com/mwilliamson/jq.py [jq.py]: https://github.com/mwilliamson/jq.py
[cyvcf2]: https://github.com/brentp/cyvcf2 [cyvcf2]: https://github.com/brentp/cyvcf2
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile [matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[Tokenizer]: https://github.com/OpenNMT/Tokenizer [Tokenizer]: https://github.com/OpenNMT/Tokenizer
[iminuit]: https://github.com/scikit-hep/iminuit [iminuit]: https://github.com/scikit-hep/iminuit
[pillow-heif]: https://github.com/bigcat88/pillow_heif [pillow-heif]: https://github.com/bigcat88/pillow_heif
[keyvi]: https://github.com/KeyviDev/keyvi [keyvi]: https://github.com/KeyviDev/keyvi
[PyGLM]: https://github.com/Zuzu-Typ/PyGLM [PyGLM]: https://github.com/Zuzu-Typ/PyGLM
[iDynTree]: https://github.com/robotology/idyntree [iDynTree]: https://github.com/robotology/idyntree
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model [power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[TgCrypto]: https://github.com/pyrogram/tgcrypto
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data [streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
[pybase64]: https://github.com/mayeut/pybase64 [pybase64]: https://github.com/mayeut/pybase64
[bx-python]: https://github.com/bxlab/bx-python
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build [Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
[bx-python]: https://github.com/bxlab/bx-python
[boost-histogram]: https://github.com/scikit-hep/boost-histogram [boost-histogram]: https://github.com/scikit-hep/boost-histogram
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc [Python-WebRTC]: https://github.com/MarshalX/python-webrtc
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example [pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
@@ -219,14 +219,14 @@ title: Working examples
[ninja]: https://github.com/scikit-build/ninja-python-distributions [ninja]: https://github.com/scikit-build/ninja-python-distributions
[etebase-py]: https://github.com/etesync/etebase-py [etebase-py]: https://github.com/etesync/etebase-py
[cf-units]: https://github.com/SciTools/cf-units [cf-units]: https://github.com/SciTools/cf-units
[numpythia]: https://github.com/scikit-hep/numpythia
[pyjet]: https://github.com/scikit-hep/pyjet
[SiPM]: https://github.com/EdoPro98/SimSiPM [SiPM]: https://github.com/EdoPro98/SimSiPM
[ril]: https://github.com/Cryptex-github/ril-py [numpythia]: https://github.com/scikit-hep/numpythia
[aalink]: https://github.com/artfwo/aalink [aalink]: https://github.com/artfwo/aalink
[pyjet]: https://github.com/scikit-hep/pyjet
[ril]: https://github.com/Cryptex-github/ril-py
[GSD]: https://github.com/glotzerlab/gsd [GSD]: https://github.com/glotzerlab/gsd
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
[werpy]: https://github.com/analyticsinmotion/werpy [werpy]: https://github.com/analyticsinmotion/werpy
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
[xmlstarlet]: https://github.com/dimitern/xmlstarlet [xmlstarlet]: https://github.com/dimitern/xmlstarlet
[pybind11 cross build example]: https://github.com/wbarnha/pybind_cmake_example_crossbuild [pybind11 cross build example]: https://github.com/wbarnha/pybind_cmake_example_crossbuild
+3 -3
View File
@@ -6,7 +6,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
pip3 install cibuildwheel==3.3.0 pip3 install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -20,7 +20,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install cibuildwheel==3.3.0 python3 -m pip install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
@@ -34,7 +34,7 @@ jobs:
- bash: | - bash: |
set -o errexit set -o errexit
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install cibuildwheel==3.3.0 pip install cibuildwheel==3.4.1
displayName: Install dependencies displayName: Install dependencies
- bash: cibuildwheel --output-dir wheelhouse . - bash: cibuildwheel --output-dir wheelhouse .
displayName: Build wheels displayName: Build wheels
+3 -3
View File
@@ -11,7 +11,7 @@ jobs:
- run: - run:
name: Build the Linux wheels. name: Build the Linux wheels.
command: | command: |
python3 -m pip install --user cibuildwheel==3.3.0 python3 -m pip install --user cibuildwheel==3.4.1
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
@@ -28,7 +28,7 @@ jobs:
- run: - run:
name: Build the Linux aarch64 wheels. name: Build the Linux aarch64 wheels.
command: | command: |
python3 -m pip install --user cibuildwheel==3.3.0 python3 -m pip install --user cibuildwheel==3.4.1
python3 -m cibuildwheel --output-dir wheelhouse python3 -m cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
@@ -44,7 +44,7 @@ jobs:
name: Build the OS X wheels. name: Build the OS X wheels.
command: | command: |
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
pip3 install cibuildwheel==3.3.0 pip3 install cibuildwheel==3.4.1
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script: install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.3.0 - python -m pip install cibuildwheel==3.4.1
run_cibuildwheel_script: run_cibuildwheel_script:
- cibuildwheel - cibuildwheel
wheels_artifacts: wheels_artifacts:
+1 -1
View File
@@ -1,6 +1,6 @@
build_and_store_wheels: &BUILD_AND_STORE_WHEELS build_and_store_wheels: &BUILD_AND_STORE_WHEELS
install_cibuildwheel_script: install_cibuildwheel_script:
- python -m pip install cibuildwheel==3.3.0 - python -m pip install cibuildwheel==3.4.1
run_cibuildwheel_script: run_cibuildwheel_script:
- cibuildwheel - cibuildwheel
wheels_artifacts: wheels_artifacts:
+7 -3
View File
@@ -48,10 +48,12 @@ jobs:
platform: pyodide platform: pyodide
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.3.0 uses: pypa/cibuildwheel@v3.4.1
env: env:
CIBW_PLATFORM: ${{ matrix.platform || 'auto' }} CIBW_PLATFORM: ${{ matrix.platform || 'auto' }}
CIBW_ARCHS: ${{ matrix.archs || 'auto' }} CIBW_ARCHS: ${{ matrix.archs || 'auto' }}
@@ -70,7 +72,9 @@ jobs:
name: Build source distribution name: Build source distribution
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build sdist - name: Build sdist
run: pipx run build --sdist run: pipx run build --sdist
+4 -2
View File
@@ -12,10 +12,12 @@ jobs:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.3.0 uses: pypa/cibuildwheel@v3.4.1
# env: # env:
# CIBW_SOME_OPTION: value # CIBW_SOME_OPTION: value
# ... # ...
+4 -2
View File
@@ -12,10 +12,12 @@ jobs:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
- name: Build wheels - name: Build wheels
run: pipx run cibuildwheel==3.3.0 run: pipx run cibuildwheel==3.4.1
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
+4 -2
View File
@@ -12,7 +12,9 @@ jobs:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14] os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-15-intel, macos-14]
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
with:
persist-credentials: false
- name: Set up QEMU - name: Set up QEMU
if: runner.os == 'Linux' && runner.arch == 'X64' if: runner.os == 'Linux' && runner.arch == 'X64'
@@ -21,7 +23,7 @@ jobs:
platforms: all platforms: all
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v3.3.0 uses: pypa/cibuildwheel@v3.4.1
env: env:
# configure cibuildwheel on Linux to build native archs ('auto'), # configure cibuildwheel on Linux to build native archs ('auto'),
# and to split the remaining architectures between the x86_64 and # and to split the remaining architectures between the x86_64 and
+3 -3
View File
@@ -12,7 +12,7 @@ linux:
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
script: script:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
- python -m pip install cibuildwheel==3.3.0 - python -m pip install cibuildwheel==3.4.1
- cibuildwheel --output-dir wheelhouse - cibuildwheel --output-dir wheelhouse
artifacts: artifacts:
paths: paths:
@@ -23,7 +23,7 @@ windows:
before_script: before_script:
- choco install python -y --allow-downgrade --version 3.12.4 - choco install python -y --allow-downgrade --version 3.12.4
- choco install git.install -y - choco install git.install -y
- py -m pip install cibuildwheel==3.3.0 - py -m pip install cibuildwheel==3.4.1
script: script:
- py -m cibuildwheel --output-dir wheelhouse --platform windows - py -m cibuildwheel --output-dir wheelhouse --platform windows
artifacts: artifacts:
@@ -35,7 +35,7 @@ windows:
macos: macos:
image: macos-14-xcode-15 image: macos-14-xcode-15
before_script: before_script:
- python3 -m pip install cibuildwheel==3.3.0 - python3 -m pip install cibuildwheel==3.4.1
script: script:
- python3 -m cibuildwheel --output-dir wheelhouse - python3 -m cibuildwheel --output-dir wheelhouse
artifacts: artifacts:
+1 -1
View File
@@ -14,7 +14,7 @@ linux:
- curl -sSL https://get.docker.com/ | sh - curl -sSL https://get.docker.com/ | sh
# Warning: This is extremely slow, be careful with how many wheels you build # Warning: This is extremely slow, be careful with how many wheels you build
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- python -m pip install cibuildwheel==3.3.0 - python -m pip install cibuildwheel==3.4.1
# Assuming your CI runner's default architecture is x86_64... # Assuming your CI runner's default architecture is x86_64...
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64 - cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
artifacts: artifacts:
-36
View File
@@ -1,36 +0,0 @@
# As written, this configuration will build your wheels on every
# commit, but will only push to PyPI on tagged commits.
os: linux
dist: jammy
language: python
python: "3.12"
jobs:
include:
# perform a linux build
- services: docker
# and a windows build
- os: windows
language: shell
before_install:
- choco upgrade python -y --version 3.12.4
- export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
# make sure it's on PATH as 'python3'
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
install:
- python3 -m pip install cibuildwheel==3.3.0
script:
# build the wheels, put them into './dist'
- python3 -m cibuildwheel --output-dir dist
deploy:
provider: pypi
username: "__token__"
skip_cleanup: true
on:
tags: true
password:
secure: "" # Set to an encrypted API token. See https://docs.travis-ci.com/user/deployment/pypi/
-33
View File
@@ -1,33 +0,0 @@
os: linux
dist: jammy
language: python
python: "3.12"
jobs:
include:
# perform a linux build
- services: docker
# perform a linux ARMv8 build
- services: docker
arch: arm64
# perform a linux PPC64LE build
- services: docker
arch: ppc64le
# perform a linux S390X build
- services: docker
arch: s390x
# and a windows build
- os: windows
language: shell
before_install:
- choco upgrade python -y --version 3.12.4
- export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
# make sure it's on PATH as 'python3'
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
install:
- python3 -m pip install cibuildwheel==3.3.0
script:
# build the wheels, put them into './wheelhouse'
- python3 -m cibuildwheel --output-dir wheelhouse
-70
View File
@@ -1,70 +0,0 @@
# In this configuration, the package is tested against multiple versions of python
# on Linux and on one version of Python on Windows. If and only if all tests pass
# will the wheels be built and deployed. Further, deployment is only initiated if
# the current branch is "main", the current commit is tagged, and the current
# repo is yours (e.g. it won't run on a Pull Request). For convenience, a source
# distribution is also created.
os: linux
dist: jammy
language: python
python: "3.12"
before_install:
- |
if [[ "$TRAVIS_OS_NAME" = windows ]]; then
choco upgrade python -y --version 3.12.4
export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
# make sure it's on PATH as 'python3'
ln -s /c/Python312/python.exe /c/Python312/python3.exe
fi
install:
- python3 -m pip install pytest
script:
- python3 -m pip install .
- pytest
stages:
- test
# Only execute deployment stage on tagged commits, and from your repository
# (e.g. not PRs). Replace with your repo name.
- name: deploy
if: tag IS PRESENT AND repo = pypa/cibuildwheel
# To only build tags that look like vX.Y.Z:
# if: tag =~ ^v\d+\.\d+\.\d+$ AND repo = pypa/cibuildwheel
jobs:
include:
# Optional: run a test on Windows
- os: windows
language: shell
name: Test on Windows
# Deploy source distribution
- stage: deploy
name: Deploy source distribution
install: python3 -m pip install build twine
script: python3 -m build --sdist --formats=gztar
after_success: python3 -m twine upload --skip-existing dist/*.tar.gz
# Deploy on linux
- stage: deploy
name: Build and deploy Linux wheels
services: docker
install: python3 -m pip install cibuildwheel==3.3.0 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
# Deploy on windows
- stage: deploy
name: Build and deploy Windows wheels
os: windows
language: shell
install: python3 -m pip install cibuildwheel==3.3.0 twine
script: python3 -m cibuildwheel --output-dir wheelhouse
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
env:
global:
- TWINE_USERNAME=__token__
# Note: TWINE_PASSWORD is set to a PyPI API token in Travis settings
+2 -2
View File
@@ -33,8 +33,8 @@ def lint(session: nox.Session) -> None:
""" """
Run the linter. Run the linter.
""" """
session.install("pre-commit") session.install("prek")
session.run("pre-commit", "run", "--all-files", *session.posargs) session.run("prek", "run", "--all-files", *session.posargs)
@nox.session(tags=["lint"]) @nox.session(tags=["lint"])
+17 -18
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "cibuildwheel" name = "cibuildwheel"
version = "3.3.0" version = "3.4.1"
description = "Build Python wheels on CI with minimal configuration." description = "Build Python wheels on CI with minimal configuration."
readme = "README.md" readme = "README.md"
license = "BSD-2-Clause" license = "BSD-2-Clause"
@@ -19,7 +19,6 @@ keywords = [
"macos", "macos",
"packaging", "packaging",
"pypi", "pypi",
"travis",
"wheel", "wheel",
"windows", "windows",
] ]
@@ -91,7 +90,7 @@ test = [
"pytest-timeout", "pytest-timeout",
"pytest-xdist", "pytest-xdist",
"pytest-rerunfailures!=16.0", "pytest-rerunfailures!=16.0",
"pytest>=6", "pytest>=9",
"setuptools", "setuptools",
"tomli_w", "tomli_w",
"validate-pyproject", "validate-pyproject",
@@ -104,11 +103,11 @@ dev = [
] ]
[tool.pytest.ini_options] [tool.pytest]
minversion = "6.0" minversion = "9.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config", "--xdoctest", "--ignore-glob=*venv*"] addopts = ["-ra", "--showlocals", "--xdoctest", "--ignore-glob=*venv*"]
strict = true
junit_family = "xunit2" junit_family = "xunit2"
xfail_strict = true
filterwarnings = ["error"] filterwarnings = ["error"]
log_level = "INFO" log_level = "INFO"
markers = [ markers = [
@@ -117,6 +116,7 @@ markers = [
"android: tests that run on Android", "android: tests that run on Android",
"pyodide: tests that run on Pyodide", "pyodide: tests that run on Pyodide",
] ]
required_plugins = ["pytest-rerunfailures"]
[tool.mypy] [tool.mypy]
python_version = "3.11" python_version = "3.11"
@@ -128,17 +128,10 @@ files = [
"noxfile.py", "noxfile.py",
] ]
warn_unused_configs = true warn_unused_configs = true
strict = true strict = true
disallow_untyped_defs = false
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = false warn_unreachable = false
[[tool.mypy.overrides]]
module = "cibuildwheel.*"
disallow_untyped_defs = true
[[tool.mypy.overrides]] [[tool.mypy.overrides]]
module = [ module = [
"setuptools._distutils", # needed even if only directly import setuptools._distutils.util "setuptools._distutils", # needed even if only directly import setuptools._distutils.util
@@ -190,6 +183,7 @@ messages_control.disable = [
] ]
[tool.ruff] [tool.ruff]
show-fixes = true
line-length = 100 line-length = 100
[tool.ruff.lint] [tool.ruff.lint]
@@ -197,6 +191,7 @@ extend-select = [
"B", # flake8-bugbear "B", # flake8-bugbear
"I", # isort "I", # isort
"ARG", # flake8-unused-arguments "ARG", # flake8-unused-arguments
"ANN", # flake8-annotations
"C4", # flake8-comprehensions "C4", # flake8-comprehensions
"EM", # flake8-errmsg "EM", # flake8-errmsg
"ICN", # flake8-import-conventions "ICN", # flake8-import-conventions
@@ -211,6 +206,7 @@ extend-select = [
"RUF", # Ruff-specific "RUF", # Ruff-specific
"SIM", # flake8-simplify "SIM", # flake8-simplify
"TID251", # flake8-tidy-imports.banned-api "TID251", # flake8-tidy-imports.banned-api
"TID252", # flake8-tidy-imports.relative-imports
"UP", # pyupgrade "UP", # pyupgrade
"YTT", # flake8-2020 "YTT", # flake8-2020
"EXE", # flake8-executable "EXE", # flake8-executable
@@ -227,15 +223,17 @@ extend-select = [
"TC", # flake8-type-checking "TC", # flake8-type-checking
] ]
ignore = [ ignore = [
"PLR", # Design related pylint codes "PLR09", # Design related pylint codes
"PLR2004", # Magic value in comparison
"RET504", "RET505", "RET508", # else after control flow "RET504", "RET505", "RET508", # else after control flow
"PT007", # Lists of tuples in Pytest "PT007", # Lists of tuples in Pytest
"PYI025", # Set as AbstractSet "PYI025", # Set as AbstractSet
"ISC001", # Conflicts with formatter
"EXE003", # Ruff doesn't like uv?
"PTH123", # open -> Path.open "PTH123", # open -> Path.open
] ]
flake8-unused-arguments.ignore-variadic-names = true flake8-unused-arguments.ignore-variadic-names = true
flake8-tidy-imports.ban-relative-imports = "all"
flake8-annotations.allow-star-arg-any = true
flake8-annotations.mypy-init-return = true
[tool.ruff.lint.flake8-tidy-imports.banned-api] [tool.ruff.lint.flake8-tidy-imports.banned-api]
"typing.Mapping".msg = "Use collections.abc.Mapping instead." "typing.Mapping".msg = "Use collections.abc.Mapping instead."
@@ -245,7 +243,8 @@ flake8-unused-arguments.ignore-variadic-names = true
"typing.Set".msg = "Use collections.abc.Set instead." "typing.Set".msg = "Use collections.abc.Set instead."
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"unit_test/*" = ["PLC1901"] "unit_test/*" = ["PLC1901", "TID252"]
"test/*" = ["TID252"]
"bin/*" = ["TID251"] "bin/*" = ["TID251"]
"cibuildwheel/resources/install_certifi.py" = ["PTH"] "cibuildwheel/resources/install_certifi.py" = ["PTH"]
+17 -6
View File
@@ -13,6 +13,7 @@ from cibuildwheel.selector import EnableGroup
from cibuildwheel.typing import PLATFORMS from cibuildwheel.typing import PLATFORMS
from cibuildwheel.venv import find_uv from cibuildwheel.venv import find_uv
from . import utils
from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_platform from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_platform
@@ -45,7 +46,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
) )
def pytest_configure(config): def pytest_configure(config: pytest.Config) -> None:
flag_enable = config.getoption("--enable") flag_enable = config.getoption("--enable")
flag_platform = config.getoption("--platform") flag_platform = config.getoption("--platform")
@@ -163,8 +164,8 @@ def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
return {"CIBW_BUILD_FRONTEND": frontend} return {"CIBW_BUILD_FRONTEND": frontend}
@pytest.fixture(params=["pip", "build", "build[uv]"]) @pytest.fixture(params=["pip", "build", "build[uv]", "uv"])
def build_frontend_env(request: pytest.FixtureRequest) -> dict[str, str]: def build_frontend_env(request: pytest.FixtureRequest) -> Generator[dict[str, str], None, None]:
frontend = request.param frontend = request.param
marks = {m.name for m in request.node.iter_markers()} marks = {m.name for m in request.node.iter_markers()}
if "android" in marks: if "android" in marks:
@@ -178,15 +179,25 @@ def build_frontend_env(request: pytest.FixtureRequest) -> dict[str, str]:
if platform in {"pyodide", "ios", "android"} and frontend == "pip": if platform in {"pyodide", "ios", "android"} and frontend == "pip":
pytest.skip(f"Can't use pip as build frontend for {platform}") pytest.skip(f"Can't use pip as build frontend for {platform}")
if platform == "pyodide" and frontend == "build[uv]": if platform == "pyodide" and frontend in {"build[uv]", "uv"}:
pytest.skip("Can't use uv with pyodide yet") pytest.skip("Can't use uv with pyodide yet")
uv_path = find_uv() uv_path = find_uv()
if uv_path is None and frontend == "build[uv]": if uv_path is None and frontend in {"build[uv]", "uv"}:
pytest.skip("Can't find uv, so skipping uv tests") pytest.skip("Can't find uv, so skipping uv tests")
if uv_path is not None and frontend == "build" and platform not in {"android", "ios"}: if uv_path is not None and frontend == "build" and platform not in {"android", "ios"}:
pytest.skip("No need to check build when uv is present") pytest.skip("No need to check build when uv is present")
return {"CIBW_BUILD_FRONTEND": frontend} # temporary workaround: uv doesn't work with graalpy yet
uses_uv = "uv" in frontend
env: dict[str, str] = {"CIBW_BUILD_FRONTEND": frontend}
if uses_uv:
utils.include_graalpy_in_expected_wheels = False
env["CIBW_SKIP"] = "gp*" # skip graalpy when using uv, until uv supports it
try:
yield env
finally:
if uses_uv:
utils.include_graalpy_in_expected_wheels = True
@pytest.fixture @pytest.fixture
+12 -5
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
import packaging.utils import packaging.utils
import pytest import pytest
@@ -21,7 +22,7 @@ basic_project = test_projects.new_c_project(
@pytest.mark.serial @pytest.mark.serial
def test_dummy_serial(): def test_dummy_serial() -> None:
"""A no-op test to ensure that at least one serial test is always found. """A no-op test to ensure that at least one serial test is always found.
Without this no-op test, CI fails on CircleCI because no serial tests are Without this no-op test, CI fails on CircleCI because no serial tests are
@@ -29,7 +30,9 @@ def test_dummy_serial():
""" """
def test(tmp_path, build_frontend_env, capfd): def test(
tmp_path: Path, build_frontend_env: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -52,7 +55,7 @@ def test(tmp_path, build_frontend_env, capfd):
@pytest.mark.skip(reason="to keep test output clean") @pytest.mark.skip(reason="to keep test output clean")
def test_sample_build(tmp_path, capfd): def test_sample_build(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -70,7 +73,9 @@ def test_sample_build(tmp_path, capfd):
@pytest.mark.parametrize( @pytest.mark.parametrize(
"enable_setting", ["", "cpython-prerelease", "pypy", "cpython-freethreading"] "enable_setting", ["", "cpython-prerelease", "pypy", "cpython-freethreading"]
) )
def test_build_identifiers(tmp_path, enable_setting, monkeypatch): def test_build_identifiers(
tmp_path: Path, enable_setting: str, monkeypatch: pytest.MonkeyPatch
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -93,7 +98,9 @@ def test_build_identifiers(tmp_path, enable_setting, monkeypatch):
(None, {"CIBW_ALLOW_EMPTY": "1"}), (None, {"CIBW_ALLOW_EMPTY": "1"}),
], ],
) )
def test_allow_empty(tmp_path, add_args, env_allow_empty): def test_allow_empty(
tmp_path: Path, add_args: list[str] | None, env_allow_empty: dict[str, str]
) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
+8 -5
View File
@@ -1,4 +1,7 @@
import textwrap import textwrap
from pathlib import Path
import pytest
from . import test_projects, utils from . import test_projects, utils
@@ -31,7 +34,7 @@ limited_api_project = test_projects.new_c_project(
limited_api_project.files["pyproject.toml"] = pyproject_toml limited_api_project.files["pyproject.toml"] = pyproject_toml
def test_abi3(tmp_path): def test_abi3(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
limited_api_project.generate(project_dir) limited_api_project.generate(project_dir)
@@ -41,7 +44,7 @@ def test_abi3(tmp_path):
add_env={ add_env={
# free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those # free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
# also limit the number of builds for test performance reasons # also limit the number of builds for test performance reasons
"CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp313t-*", "CIBW_BUILD": "cp39-* cp310-* pp310-* gp312_250-* cp312-* cp314t-*",
"CIBW_ENABLE": "all", "CIBW_ENABLE": "all",
}, },
) )
@@ -62,7 +65,7 @@ def test_abi3(tmp_path):
python_abi_tags=[ python_abi_tags=[
"cp39-cp39", "cp39-cp39",
"cp310-abi3", # <-- ABI3, works with 3.10 and 3.12 "cp310-abi3", # <-- ABI3, works with 3.10 and 3.12
"cp313-cp313t", "cp314-cp314t",
"pp310-pypy310_pp73", "pp310-pypy310_pp73",
"graalpy312-graalpy250_312_native", "graalpy312-graalpy250_312_native",
], ],
@@ -178,7 +181,7 @@ ctypes_project.files["test/add_test.py"] = textwrap.dedent(
ctypes_project.files["pyproject.toml"] = pyproject_toml ctypes_project.files["pyproject.toml"] = pyproject_toml
def test_abi_none(tmp_path, capfd): def test_abi_none(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
ctypes_project.generate(project_dir) ctypes_project.generate(project_dir)
@@ -189,7 +192,7 @@ def test_abi_none(tmp_path, capfd):
"CIBW_TEST_REQUIRES": "pytest", "CIBW_TEST_REQUIRES": "pytest",
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test", "CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test",
# limit the number of builds for test performance reasons # limit the number of builds for test performance reasons
"CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION), "CIBW_BUILD": "cp38-* cp{}{}-* cp314t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION),
"CIBW_ENABLE": "all", "CIBW_ENABLE": "all",
}, },
) )
+201 -22
View File
@@ -2,9 +2,11 @@ import os
import platform import platform
import re import re
import sys import sys
import typing
from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from shutil import rmtree from shutil import rmtree, which
from subprocess import CalledProcessError from subprocess import CalledProcessError
from textwrap import dedent from textwrap import dedent
from zipfile import ZipFile from zipfile import ZipFile
@@ -52,8 +54,10 @@ if "ANDROID_HOME" not in os.environ:
# Many CI services don't support running the Android emulator: see platforms.md. # Many CI services don't support running the Android emulator: see platforms.md.
supports_emulator = (not ci) or ("GITHUB_ACTIONS" in os.environ and platform.system() == "Linux") supports_emulator = (not ci) or ("GITHUB_ACTIONS" in os.environ and platform.system() == "Linux")
T = typing.TypeVar("T", bound=Callable[..., typing.Any])
def needs_emulator(test):
def needs_emulator(test: T) -> T:
# All copies of the testbed app run on the same emulator with the same # All copies of the testbed app run on the same emulator with the same
# application ID, so these tests must be run serially. # application ID, so these tests must be run serially.
test = pytest.mark.serial(test) test = pytest.mark.serial(test)
@@ -85,7 +89,7 @@ cp313_env = {
} }
def test_android_home(tmp_path, capfd): def test_android_home(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
env = os.environ.copy() env = os.environ.copy()
del env["ANDROID_HOME"] del env["ANDROID_HOME"]
@@ -100,7 +104,7 @@ def test_android_home(tmp_path, capfd):
# a build, which is marked as serial so it will run before the parallel tests, but isn't # a build, which is marked as serial so it will run before the parallel tests, but isn't
# marked as needs_emulator so it will run on all CI platforms. # marked as needs_emulator so it will run on all CI platforms.
@pytest.mark.serial @pytest.mark.serial
def test_expected_wheels(tmp_path, spam_env): def test_expected_wheels(tmp_path: Path, spam_env: dict[str, str]) -> None:
# Since this test covers all Python versions, check the cross venv. # Since this test covers all Python versions, check the cross venv.
test_module = "_cross_venv_test_android" test_module = "_cross_venv_test_android"
project = new_c_project(setup_py_add=f"import {test_module}") project = new_c_project(setup_py_add=f"import {test_module}")
@@ -119,7 +123,7 @@ def test_expected_wheels(tmp_path, spam_env):
@needs_emulator @needs_emulator
def test_frontend_good(tmp_path, build_frontend_env): def test_frontend_good(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
wheels = cibuildwheel_run( wheels = cibuildwheel_run(
tmp_path, tmp_path,
@@ -129,7 +133,7 @@ def test_frontend_good(tmp_path, build_frontend_env):
@pytest.mark.parametrize("frontend", ["pip"]) @pytest.mark.parametrize("frontend", ["pip"])
def test_frontend_bad(frontend, tmp_path, capfd): def test_frontend_bad(frontend: str, tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run( cibuildwheel_run(
@@ -140,7 +144,7 @@ def test_frontend_bad(frontend, tmp_path, capfd):
@needs_emulator @needs_emulator
def test_archs(tmp_path, capfd): def test_archs(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
# Build all architectures while checking the handling of the `before` commands. # Build all architectures while checking the handling of the `before` commands.
@@ -189,7 +193,7 @@ def test_archs(tmp_path, capfd):
pytest.fail(f"Unexpected line: {line!r}") pytest.fail(f"Unexpected line: {line!r}")
def test_build_requires(tmp_path, capfd): def test_build_requires(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# Build-time requirements should be installed for the build platform, not for Android. Prove # Build-time requirements should be installed for the build platform, not for Android. Prove
# this by installing some non-pure-Python requirements and using them in setup.py. # this by installing some non-pure-Python requirements and using them in setup.py.
# #
@@ -226,13 +230,13 @@ def test_build_requires(tmp_path, capfd):
@pytest.fixture @pytest.fixture
def spam_env(tmp_path): def spam_env(tmp_path: Path) -> dict[str, str]:
project = new_c_project() project = new_c_project()
project.files["test_spam.py"] = dedent( project.files["test_spam.py"] = dedent(
"""\ """\
import spam import spam
def test_spam(): def test_spam() -> None:
assert spam.filter("ham") assert spam.filter("ham")
assert not spam.filter("spam") assert not spam.filter("spam")
print("Spam test passed") print("Spam test passed")
@@ -240,7 +244,7 @@ def spam_env(tmp_path):
) )
project.files["test_empty.py"] = dedent( project.files["test_empty.py"] = dedent(
"""\ """\
def test_empty(): def test_empty() -> None:
pass pass
""" """
) )
@@ -265,7 +269,13 @@ def spam_env(tmp_path):
("pytest test_spam.py", "=== 1 passed in "), ("pytest test_spam.py", "=== 1 passed in "),
], ],
) )
def test_test_command_good(command, expected_output, tmp_path, spam_env, capfd): def test_test_command_good(
command: str,
expected_output: str,
tmp_path: Path,
spam_env: dict[str, str],
capfd: pytest.CaptureFixture[str],
) -> None:
cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command}) cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command})
stdout, stderr = capfd.readouterr() stdout, stderr = capfd.readouterr()
assert expected_output in stdout assert expected_output in stdout
@@ -300,7 +310,13 @@ BAD_PLACEHOLDER_ERROR = (
("pytest test_ham.py", "not found: test_ham.py"), ("pytest test_ham.py", "not found: test_ham.py"),
], ],
) )
def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd): def test_test_command_bad(
command: str,
expected_output: str,
tmp_path: Path,
spam_env: dict[str, str],
capfd: pytest.CaptureFixture[str],
) -> None:
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command}) cibuildwheel_run(tmp_path, add_env={**spam_env, "CIBW_TEST_COMMAND": command})
assert expected_output in capfd.readouterr().err assert expected_output in capfd.readouterr().err
@@ -314,7 +330,9 @@ def test_test_command_bad(command, expected_output, tmp_path, spam_env, capfd):
("-E", 1), ("-E", 1),
], ],
) )
def test_test_command_python_options(options, expected, tmp_path, capfd): def test_test_command_python_options(
options: str, expected: int, tmp_path: Path, capfd: pytest.CaptureFixture[str]
) -> None:
project = new_c_project() project = new_c_project()
project.generate(tmp_path) project.generate(tmp_path)
@@ -330,7 +348,9 @@ def test_test_command_python_options(options, expected, tmp_path, capfd):
@needs_emulator @needs_emulator
def test_package_subdir(tmp_path, spam_env, capfd): def test_package_subdir(
tmp_path: Path, spam_env: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
spam_paths = list(tmp_path.iterdir()) spam_paths = list(tmp_path.iterdir())
package_dir = tmp_path / "package" package_dir = tmp_path / "package"
package_dir.mkdir() package_dir.mkdir()
@@ -345,7 +365,7 @@ def test_package_subdir(tmp_path, spam_env, capfd):
@needs_emulator @needs_emulator
def test_no_test_sources(tmp_path, capfd): def test_no_test_sources(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
with pytest.raises(CalledProcessError): with pytest.raises(CalledProcessError):
cibuildwheel_run( cibuildwheel_run(
@@ -359,17 +379,17 @@ def test_no_test_sources(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_environment_markers(tmp_path): def test_environment_markers(tmp_path: Path) -> None:
project = new_c_project() project = new_c_project()
test_filename = "test_environment_markers.py" test_filename = "test_environment_markers.py"
project.files[test_filename] = dedent( project.files[test_filename] = dedent(
"""\ """\
import pytest import pytest
def test_android(): def test_android() -> None:
import certifi import certifi
def test_not_android(): def test_not_android() -> None:
try: try:
import platformdirs import platformdirs
except ImportError: except ImportError:
@@ -392,7 +412,7 @@ def test_environment_markers(tmp_path):
@needs_emulator @needs_emulator
def test_verbosity(tmp_path, capfd): def test_verbosity(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
new_c_project().generate(tmp_path) new_c_project().generate(tmp_path)
test_env = { test_env = {
**cp313_env, **cp313_env,
@@ -418,7 +438,7 @@ def test_verbosity(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_api_level(tmp_path, capfd): def test_api_level(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project = new_c_project() project = new_c_project()
project.files["pyproject.toml"] = dedent( project.files["pyproject.toml"] = dedent(
"""\ """\
@@ -450,7 +470,7 @@ def test_api_level(tmp_path, capfd):
@needs_emulator @needs_emulator
def test_libcxx(tmp_path, capfd): def test_libcxx(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
output_dir = tmp_path / "output" output_dir = tmp_path / "output"
@@ -496,3 +516,162 @@ def test_libcxx(tmp_path, capfd):
assert len(wheels) == 1 assert len(wheels) == 1
for name in ZipFile(output_dir / wheels[0]).namelist(): for name in ZipFile(output_dir / wheels[0]).namelist():
assert ".libs" not in name assert ".libs" not in name
@needs_emulator
def test_setuptools_rust(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""
Test Android cross-compilation using the setuptools-rust toolchain.
"""
if not which("rustup") or not which("cargo"):
pytest.skip("rustup and cargo are required for this test")
# Initialize a basic project and override files for setuptools-rust
project = new_c_project()
project.files["pyproject.toml"] = dedent(
"""\
[build-system]
requires = ["setuptools", "wheel", "setuptools-rust"]
"""
)
project.files["setup.py"] = dedent(
"""\
from setuptools import setup
from setuptools_rust import Binding, RustExtension
setup(
name="spam",
version="0.1.0",
rust_extensions=[RustExtension("spam.rust_ext", binding=Binding.PyO3)],
zip_safe=False,
)
"""
)
project.files["Cargo.toml"] = dedent(
"""\
[package]
name = "rust_ext"
version = "0.1.0"
edition = "2021"
[lib]
name = "rust_ext"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.23.3", features = ["extension-module"] }
"""
)
# Create the Rust source directory and file
(tmp_path / "src").mkdir()
project.files["src/lib.rs"] = dedent(
"""\
use pyo3::prelude::*;
#[pyfunction]
fn hello() -> PyResult<String> {
Ok("Hello from Rust via setuptools-rust!".to_string())
}
#[pymodule]
fn rust_ext(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(hello, m)?)?;
Ok(())
}
"""
)
project.generate(tmp_path)
# Command to verify the built extension on the Android emulator
test_command = "python -c 'import spam.rust_ext; print(spam.rust_ext.hello())'"
# Run cibuildwheel to build and test the wheel
wheels = cibuildwheel_run(
tmp_path,
add_env={
**cp313_env,
"CIBW_TEST_COMMAND": test_command,
"CIBW_BUILD_VERBOSITY": "1",
},
)
# Verification
assert len(wheels) == 1
stdout = capfd.readouterr().out
assert "Hello from Rust via setuptools-rust!" in stdout
@needs_emulator
def test_maturin(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
"""
Test Android cross-compilation using the maturin backend.
"""
if not which("rustup") or not which("cargo"):
pytest.skip("rustup and cargo are required for this test")
project = new_c_project()
project.files["pyproject.toml"] = dedent(
"""\
[build-system]
# maturin >= 1.11.0 is required for reliable Android cross-compilation support.
requires = ["maturin>=1.11.0,<2.0"]
build-backend = "maturin"
[project]
name = "spam"
version = "0.1.0"
"""
)
project.files["Cargo.toml"] = dedent(
"""\
[package]
name = "spam"
version = "0.1.0"
edition = "2021"
[lib]
name = "spam"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.23.3", features = ["extension-module"] }
"""
)
(tmp_path / "src").mkdir()
project.files["src/lib.rs"] = dedent(
"""\
use pyo3::prelude::*;
#[pyfunction]
fn hello() -> PyResult<String> {
Ok("Hello from Rust via maturin!".to_string())
}
#[pymodule]
fn spam(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(hello, m)?)?;
Ok(())
}
"""
)
project.generate(tmp_path)
(tmp_path / "setup.py").unlink()
test_command = "python -c 'import spam; print(spam.hello())'"
wheels = cibuildwheel_run(
tmp_path,
add_env={
**cp313_env,
"CIBW_TEST_COMMAND": test_command,
"CIBW_BUILD_VERBOSITY": "1",
},
)
assert len(wheels) == 1
stdout = capfd.readouterr().out
assert "Hello from Rust via maturin!" in stdout
+4 -3
View File
@@ -1,5 +1,6 @@
import subprocess import subprocess
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -29,7 +30,7 @@ project_with_before_build_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_before_build_asserts.generate(project_dir) project_with_before_build_asserts.generate(project_dir)
@@ -61,7 +62,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_failing_command(tmp_path): def test_failing_command(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
@@ -75,7 +76,7 @@ def test_failing_command(tmp_path):
) )
def test_cwd(tmp_path): def test_cwd(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
+4 -3
View File
@@ -1,5 +1,6 @@
import subprocess import subprocess
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -36,7 +37,7 @@ project_with_before_build_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_before_build_asserts.generate(project_dir) project_with_before_build_asserts.generate(project_dir)
@@ -65,7 +66,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_failing_command(tmp_path): def test_failing_command(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
@@ -79,7 +80,7 @@ def test_failing_command(tmp_path):
) )
def test_cwd(tmp_path): def test_cwd(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
test_projects.new_c_project().generate(project_dir) test_projects.new_c_project().generate(project_dir)
+5 -3
View File
@@ -1,3 +1,5 @@
from pathlib import Path
from . import test_projects, utils from . import test_projects, utils
before_test_project = test_projects.new_c_project() before_test_project = test_projects.new_c_project()
@@ -11,7 +13,7 @@ PROJECT_DIR = Path(__file__).parent.parent.resolve()
class TestBeforeTest(TestCase): class TestBeforeTest(TestCase):
def test_version(self): def test_version(self) -> None:
# assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step # assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step
# is the same one as is currently running. # is the same one as is currently running.
# because of use symlinks in MacOS run this test is also need # because of use symlinks in MacOS run this test is also need
@@ -20,7 +22,7 @@ class TestBeforeTest(TestCase):
print('sys.version', sys.version) print('sys.version', sys.version)
assert stored_version == sys.version assert stored_version == sys.version
def test_prefix(self): def test_prefix(self) -> None:
# check that the prefix also was written # check that the prefix also was written
stored_prefix = PROJECT_DIR.joinpath('pythonprefix_bt.txt').read_text() stored_prefix = PROJECT_DIR.joinpath('pythonprefix_bt.txt').read_text()
print('stored_prefix', stored_prefix) print('stored_prefix', stored_prefix)
@@ -32,7 +34,7 @@ class TestBeforeTest(TestCase):
""" """
def test(tmp_path, build_frontend_env): def test(tmp_path: Path, build_frontend_env: dict[str, str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
before_test_project.generate(project_dir) before_test_project.generate(project_dir)
test_project_dir = project_dir / "dependency" test_project_dir = project_dir / "dependency"
+6 -4
View File
@@ -1,9 +1,9 @@
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
from . import utils from . import test_projects, utils
from .test_projects.c import new_c_project
@pytest.mark.parametrize( @pytest.mark.parametrize(
@@ -13,8 +13,10 @@ from .test_projects.c import new_c_project
"build", "build",
], ],
) )
def test_build_frontend_args(tmp_path, capfd, frontend_name): def test_build_frontend_args(
project = new_c_project() tmp_path: Path, capfd: pytest.CaptureFixture[str], frontend_name: str
) -> None:
project = test_projects.new_c_project()
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project.generate(project_dir) project.generate(project_dir)
+2 -1
View File
@@ -1,4 +1,5 @@
import textwrap import textwrap
from pathlib import Path
from . import test_projects, utils from . import test_projects, utils
@@ -15,7 +16,7 @@ project_with_skip_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_skip_asserts.generate(project_dir) project_with_skip_asserts.generate(project_dir)
+6 -2
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import pytest import pytest
from . import test_projects, utils from . import test_projects, utils
@@ -5,7 +7,9 @@ from . import test_projects, utils
basic_project = test_projects.new_c_project() basic_project = test_projects.new_c_project()
def test_podman(tmp_path, capfd, request): def test_podman(
tmp_path: Path, capfd: pytest.CaptureFixture[str], request: pytest.FixtureRequest
) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
@@ -35,7 +39,7 @@ def test_podman(tmp_path, capfd, request):
assert "test log statement from before-all" in captured.out assert "test log statement from before-all" in captured.out
def test_create_args(tmp_path, capfd): def test_create_args(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
+2 -1
View File
@@ -1,5 +1,6 @@
import platform import platform
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -22,7 +23,7 @@ dockcross_only_project = test_projects.new_c_project(
@pytest.mark.usefixtures("docker_cleanup") @pytest.mark.usefixtures("docker_cleanup")
def test(tmp_path): def test(tmp_path: Path) -> None:
if utils.get_platform() != "linux": if utils.get_platform() != "linux":
pytest.skip("the test is only relevant to the linux build") pytest.skip("the test is only relevant to the linux build")
if platform.machine() not in ["x86_64", "i686"]: if platform.machine() not in ["x86_64", "i686"]:
+5 -3
View File
@@ -1,3 +1,5 @@
from pathlib import Path
import jinja2 import jinja2
from . import utils from . import utils
@@ -52,7 +54,7 @@ cpp_test_project.files["setup.py"] = jinja2.Template(setup_py_template)
cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template) cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template)
def test_cpp11(tmp_path): def test_cpp11(tmp_path: Path) -> None:
# This test checks that the C++11 standard is supported # This test checks that the C++11 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp11_project = cpp_test_project.copy() cpp11_project = cpp_test_project.copy()
@@ -68,7 +70,7 @@ def test_cpp11(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cpp14(tmp_path): def test_cpp14(tmp_path: Path) -> None:
# This test checks that the C++14 standard is supported # This test checks that the C++14 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp14_project = cpp_test_project.copy() cpp14_project = cpp_test_project.copy()
@@ -84,7 +86,7 @@ def test_cpp14(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_cpp17(tmp_path): def test_cpp17(tmp_path: Path) -> None:
# This test checks that the C++17 standard is supported # This test checks that the C++17 standard is supported
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
cpp17_project = cpp_test_project.copy() cpp17_project = cpp_test_project.copy()
+3 -2
View File
@@ -1,6 +1,7 @@
import subprocess import subprocess
import textwrap import textwrap
from contextlib import nullcontext as does_not_raise from contextlib import nullcontext as does_not_raise
from pathlib import Path
import pytest import pytest
@@ -30,7 +31,7 @@ shutil.copy(wheel, dest)
""" """
def test(tmp_path, capfd): def test(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
# this test checks that a generated wheel name shall be unique in a given cibuildwheel run # this test checks that a generated wheel name shall be unique in a given cibuildwheel run
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
@@ -68,7 +69,7 @@ def test(tmp_path, capfd):
], ],
ids=["no-placeholder", "package-placeholder", "project-placeholder"], ids=["no-placeholder", "package-placeholder", "project-placeholder"],
) )
def test_repair_wheel_command_structure(tmp_path, repair_command): def test_repair_wheel_command_structure(tmp_path: Path, repair_command: str) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project = test_projects.new_c_project() project = test_projects.new_c_project()
project.files["repair.py"] = textwrap.dedent(""" project.files["repair.py"] = textwrap.dedent("""
+9 -3
View File
@@ -36,7 +36,9 @@ for name, expected_version in expected_versions.items():
""" """
def test_check_versions_script(tmp_path, build_frontend_env_nouv, capfd): def test_check_versions_script(
tmp_path: Path, build_frontend_env_nouv: dict[str, str], capfd: pytest.CaptureFixture[str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("we don't test dependency versions on linux, refer to other tests") pytest.skip("we don't test dependency versions on linux, refer to other tests")
@@ -76,7 +78,9 @@ def get_versions_from_constraint_file(constraint_file: Path) -> dict[str, str]:
@pytest.mark.parametrize("python_version", ["3.8", "3.12"]) @pytest.mark.parametrize("python_version", ["3.8", "3.12"])
def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv): def test_pinned_versions(
tmp_path: Path, python_version: str, build_frontend_env_nouv: dict[str, str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
if python_version != "3.12" and utils.get_platform() == "pyodide": if python_version != "3.12" and utils.get_platform() == "pyodide":
@@ -127,7 +131,9 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
@pytest.mark.parametrize("method", ["inline", "file"]) @pytest.mark.parametrize("method", ["inline", "file"])
def test_dependency_constraints(method, tmp_path, build_frontend_env_nouv): def test_dependency_constraints(
method: str, tmp_path: Path, build_frontend_env_nouv: dict[str, str]
) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead") pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
+4 -3
View File
@@ -1,5 +1,6 @@
import itertools import itertools
import subprocess import subprocess
from pathlib import Path
import pytest import pytest
@@ -10,13 +11,13 @@ project_with_a_test = test_projects.new_c_project()
project_with_a_test.files["test/spam_test.py"] = r""" project_with_a_test.files["test/spam_test.py"] = r"""
import spam import spam
def test_spam(): def test_spam() -> None:
assert spam.filter("spam") == 0 assert spam.filter("spam") == 0
assert spam.filter("ham") != 0 assert spam.filter("ham") != 0
""" """
def test(tmp_path, request): def test(tmp_path: Path, request: pytest.FixtureRequest) -> None:
archs = request.config.getoption("--run-emulation") archs = request.config.getoption("--run-emulation")
if archs is None: if archs is None:
pytest.skip("needs --run-emulation option to run") pytest.skip("needs --run-emulation option to run")
@@ -45,7 +46,7 @@ def test(tmp_path, request):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_setting_arch_on_other_platforms(tmp_path, capfd): def test_setting_arch_on_other_platforms(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
if utils.get_platform() == "linux": if utils.get_platform() == "linux":
pytest.skip("this test checks the behaviour on platforms other than linux") pytest.skip("this test checks the behaviour on platforms other than linux")
+4 -3
View File
@@ -2,6 +2,7 @@ import os
import subprocess import subprocess
import sys import sys
import textwrap import textwrap
from pathlib import Path
import pytest import pytest
@@ -33,7 +34,7 @@ project_with_environment_asserts = test_projects.new_c_project(
) )
def test(tmp_path): def test(tmp_path: Path) -> None:
python_echo = f"'{sys.executable}' -c \"import sys; print(*sys.argv[1:])\"" python_echo = f"'{sys.executable}' -c \"import sys; print(*sys.argv[1:])\""
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
project_with_environment_asserts.generate(project_dir) project_with_environment_asserts.generate(project_dir)
@@ -55,7 +56,7 @@ def test(tmp_path):
assert set(actual_wheels) == set(expected_wheels) assert set(actual_wheels) == set(expected_wheels)
def test_overridden_path(tmp_path, capfd): def test_overridden_path(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None:
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
output_dir = tmp_path / "output" output_dir = tmp_path / "output"
@@ -108,7 +109,7 @@ def test_overridden_path(tmp_path, capfd):
), ),
], ],
) )
def test_overridden_pip_constraint(tmp_path, build_frontend): def test_overridden_pip_constraint(tmp_path: Path, build_frontend: str) -> None:
""" """
Verify that users can use PIP_CONSTRAINT to specify a specific version of Verify that users can use PIP_CONSTRAINT to specify a specific version of
a build-system.requires dependency, by asserting the version of pytz in the a build-system.requires dependency, by asserting the version of pytz in the

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