Compare commits

..
5 Commits
73 changed files with 1474 additions and 1613 deletions
+3 -3
View File
@@ -19,16 +19,16 @@ jobs:
contents: read contents: read
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
allow-prereleases: true allow-prereleases: true
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- name: Install tooling - name: Install tooling
run: | run: |
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
dist: dist:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
@@ -37,7 +37,7 @@ jobs:
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@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with: with:
subject-path: "dist/cibuildwheel-*" subject-path: "dist/cibuildwheel-*"
+23 -26
View File
@@ -23,7 +23,7 @@ on:
- .travis.yml - .travis.yml
- README.md - README.md
- azure-pipelines.yml - azure-pipelines.yml
- properdocs.yml - mkdocs.yml
- noxfile.py - noxfile.py
workflow_dispatch: workflow_dispatch:
# allow manual runs on branches without a PR # allow manual runs on branches without a PR
@@ -39,14 +39,14 @@ jobs:
name: Linters (mypy, ruff, etc.) name: Linters (mypy, ruff, etc.)
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- uses: j178/prek-action@e98a699c41eb69ab013a45817a0406469a748f8d # v2.0.5 - uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4
- name: PyLint checks - name: PyLint checks
run: uvx nox -s pylint -- --output-format=github run: uvx nox -s pylint -- --output-format=github
@@ -55,14 +55,14 @@ jobs:
needs: lint needs: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
name: Install Python name: Install Python
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.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: Generate a sample project
@@ -117,16 +117,16 @@ jobs:
test_select: android test_select: android
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - 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@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- name: Free up disk space - name: Free up disk space
if: runner.os == 'Linux' && matrix.test_select != 'android' if: runner.os == 'Linux' && matrix.test_select != 'android'
@@ -139,7 +139,7 @@ jobs:
# 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@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
- name: Set up Xcode - name: Set up Xcode
if: ${{ startsWith(matrix.os, 'macos-15') }} if: ${{ startsWith(matrix.os, 'macos-15') }}
@@ -168,9 +168,6 @@ jobs:
if [[ -n "$GITHUB_PR_LABEL_CI_GRAALPY" ]]; then if [[ -n "$GITHUB_PR_LABEL_CI_GRAALPY" ]]; then
CIBW_ENABLE+=" graalpy" CIBW_ENABLE+=" graalpy"
fi fi
if [[ -n "$GITHUB_PR_LABEL_CI_PYPY_EOL" ]]; then
CIBW_ENABLE+=" pypy-eol"
fi
fi fi
echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV echo "CIBW_ENABLE=${CIBW_ENABLE}" >> $GITHUB_ENV
@@ -250,13 +247,13 @@ jobs:
outputs: outputs:
archs: ${{ steps.archs.outputs.archs }} archs: ${{ steps.archs.outputs.archs }}
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.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
@@ -275,18 +272,18 @@ jobs:
matrix: matrix:
arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }} arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }}
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with: with:
python-version: "3.x" python-version: "3.x"
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.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@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
- name: Run the emulation tests - name: Run the emulation tests
env: env:
@@ -299,14 +296,14 @@ jobs:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
timeout-minutes: 180 timeout-minutes: 180
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - 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@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
- name: Install dependencies - name: Install dependencies
run: uv sync --no-dev --group test run: uv sync --no-dev --group test
@@ -351,7 +348,7 @@ jobs:
- os: macos-15 - os: macos-15
test_select: android test_select: android
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Download a sample project - name: Download a sample project
+2 -3
View File
@@ -37,11 +37,11 @@ jobs:
permission-contents: write permission-contents: write
permission-pull-requests: write permission-pull-requests: write
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
with: with:
python-version: "3.14" python-version: "3.14"
@@ -69,5 +69,4 @@ jobs:
labels: | labels: |
CI: GraalPy CI: GraalPy
CI: PyPy CI: PyPy
CI: PyPy EoL
dependencies dependencies
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
+2 -2
View File
@@ -16,9 +16,9 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with: with:
persist-credentials: false persist-credentials: false
- name: Run zizmor 🌈 - name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6
+3 -3
View File
@@ -18,7 +18,7 @@ repos:
exclude: ^cibuildwheel/resources/android/android.patch$ exclude: ^cibuildwheel/resources/android/android.patch$
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: c59bba8fb259db0fec2bbb77ad8ba51ea7341b56 # frozen: v0.15.20 rev: 0671d8ab202c4ac093b78433ae5baf74f3fc7246 # frozen: v0.15.15
hooks: hooks:
- id: ruff-check - id: ruff-check
args: ["--fix"] args: ["--fix"]
@@ -77,7 +77,7 @@ repos:
additional_dependencies: [cogapp>=3.5] additional_dependencies: [cogapp>=3.5]
- repo: https://github.com/henryiii/flake8-lazy - repo: https://github.com/henryiii/flake8-lazy
rev: 5fed9a818f2583f0403aed779bf2b6c9aa8d25f4 # frozen: v0.8.5 rev: 65b94e97b1091634368592d98072160842265fe4 # frozen: v0.8.2
hooks: hooks:
- id: flake8-lazy - id: flake8-lazy
args: ["--apply=set"] args: ["--apply=set"]
@@ -93,7 +93,7 @@ repos:
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 1a4bb160cab6417b3045e1b37b6b72449243e658 # frozen: 0.37.4 rev: 943377262562a12b57292fc98fabd7dbf81451fe # frozen: 0.37.2
hooks: hooks:
- id: check-dependabot - id: check-dependabot
- id: check-github-actions - id: check-github-actions
+1 -1
View File
@@ -8,4 +8,4 @@ build:
- asdf plugin add uv - asdf plugin add uv
- asdf install uv latest - asdf install uv latest
- asdf global uv latest - asdf global uv latest
- NO_COLOR=1 uv run --python 3.14 --managed-python --no-dev --group docs properdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html - NO_COLOR=1 uv run --python 3.14 --managed-python --no-dev --group docs mkdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html
+2 -2
View File
@@ -11,7 +11,7 @@
- `nox -s tests -- test -k before_build` — single integration test/file via pytest `-k`. - `nox -s tests -- test -k before_build` — single integration test/file via pytest `-k`.
- `nox -s lint` — run all linters (pre-commit/prek). - `nox -s lint` — run all linters (pre-commit/prek).
- `nox -s pylint` — run pylint separately (not in pre-commit). - `nox -s pylint` — run pylint separately (not in pre-commit).
- `nox -s docs`properdocs serve (interactive) or build (non-interactive). - `nox -s docs`mkdocs serve (interactive) or build (non-interactive).
- Set up local dev env at `.venv`: `uv sync` (dependency groups used). - Set up local dev env at `.venv`: `uv sync` (dependency groups used).
## Project layout ## Project layout
@@ -19,7 +19,7 @@
- `test/`**integration tests** (expensive, run actual wheel builds). - `test/`**integration tests** (expensive, run actual wheel builds).
- `unit_test/`**unit tests** (fast, no wheel builds). - `unit_test/`**unit tests** (fast, no wheel builds).
- `bin/` — maintainer scripts (update pins, generate README tables, schema, etc.). - `bin/` — maintainer scripts (update pins, generate README tables, schema, etc.).
- `docs/`properdocs (MkDocs fork) source. - `docs/`mkdocs source.
## Testing specifics ## Testing specifics
- Three test suites exist, run in this order by `bin/run_tests.py`: - Three test suites exist, run in this order by `bin/run_tests.py`:
+10 -26
View File
@@ -98,7 +98,7 @@ jobs:
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==4.1.1 run: python -m pip install cibuildwheel==4.1.0
- name: Build wheels - name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse run: python -m cibuildwheel --output-dir wheelhouse
@@ -189,8 +189,8 @@ Here are some repos that use cibuildwheel.
|-----------------------------------|----|----|:------| |-----------------------------------|----|----|:------|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. | | [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [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 |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The fundamental package for scientific computing with Python. |
| [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][] ![pyodide icon][] | The fundamental package for scientific computing with Python. |
| [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][] ![pyodide icon][] | The venerable Matplotlib, a Python library with C++ portions | | [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide 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. | | [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. |
@@ -200,8 +200,8 @@ Here are some repos that use cibuildwheel.
[scikit-learn]: https://github.com/scikit-learn/scikit-learn [scikit-learn]: https://github.com/scikit-learn/scikit-learn
[duckdb]: https://github.com/duckdb/duckdb [duckdb]: https://github.com/duckdb/duckdb
[NumPy]: https://github.com/numpy/numpy
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq [pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[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 [Tornado]: https://github.com/tornadoweb/tornado
@@ -239,28 +239,6 @@ Changelog
<!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] --> <!-- [[[cog from readme_changelog import mini_changelog; print(mini_changelog()) ]]] -->
### v4.1.1
_24 July 2026_
- ✨ Adds `pyodide-build` as a separate [`build-frontend`](https://cibuildwheel.pypa.io/en/stable/options/#build-frontend), now the default frontend for Pyodide, with verbosity flags handling. Any other frontend is ignored with a warning on Pyodide. (#2609, #2945)
- 🔐 Uses digests instead of tags for pinned container images, strengthening supply-chain security. The human-readable tags remain as comments in `pinned_docker_images.cfg`. (#2915)
- 🐛 Fixes platform-specific [`test-runtime`](https://cibuildwheel.pypa.io/en/stable/options/#test-runtime) environment variables (e.g. `CIBW_TEST_RUNTIME_ANDROID`) not being honored (#2941)
- 🐛 Fixes quoting of [`test-requires`](https://cibuildwheel.pypa.io/en/stable/options/#test-requires) and [`audit-requires`](https://cibuildwheel.pypa.io/en/stable/options/#audit-requires) so PEP 508 specifiers containing spaces work (#2913)
- 🐛 Makes [`archs`](https://cibuildwheel.pypa.io/en/stable/options/#archs) parsing case-insensitive and platform-aware, so e.g. `arm64` works on Windows (#2920)
- 🐛 Uses an absolute path for the `{project}` placeholder in [`config-settings`](https://cibuildwheel.pypa.io/en/stable/options/#config-settings) (#2934)
- 🐛 Validates the [`pyodide-version`](https://cibuildwheel.pypa.io/en/stable/options/#pyodide-version) option against the build identifier with a clear error (#2925)
- 🐛 Fixes PyPy installs on macOS after PyPy switched its downloads from `.tar.bz2` to `.tar.gz` (#2939)
- 🐛 Makes a matching `python3-config` available in the build and test venvs on macOS (#2922)
- 🛠 Updates dependencies and container pins (#2917, #2935, #2939)
- 🛠 Updates Android tests to current Python versions and the new test repository URL (#2933)
- 🛠 Drops the `orjson` dependency, no longer used by mypy 2+ (#2923)
- 📚 Builds the docs with properdocs, a MkDocs fork (#2946)
- 📚 Adds the missing `cp314-pyodide_wasm32` entry to the build identifier table (#2947)
- 📚 Removes outdated notes about the `pip wheel` build frontend and ClearLinux (#2926)
- 💼 Adds a "CI: PyPy EoL" PR label to run PyPy EoL tests on PRs (#2930)
- 💼 Updates CI action pins and pre-commit hooks (#2914, #2932, #2938, #2940, #2942, #2943)
### v4.1.0 ### v4.1.0
_12 June 2026_ _12 June 2026_
@@ -350,7 +328,13 @@ _5 March 2026_
- ✨ Add support for quiet setting on `build` and `uv` from the cibuildwheel `build-verbosity` setting. (#2737) - ✨ 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) - 📚 Docs updates, including guidance on using Meson on Windows (#2718)
<!-- [[[end]]] (sum: kQUcUVgqfM) --> ### v3.3.1
_5 January 2026_
- 🛠 Update dependencies and container pins, including updating to CPython 3.14.2. (#2708)
<!-- [[[end]]] (sum: s3fkxPyqwC) -->
--- ---
+1 -1
View File
@@ -28,7 +28,7 @@ branding:
runs: runs:
using: composite using: composite
steps: steps:
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: python id: python
with: with:
python-version: "3.11 - 3.14" python-version: "3.11 - 3.14"
+1 -1
View File
@@ -12,7 +12,7 @@ pr:
- .readthedocs.yml - .readthedocs.yml
- .travis.yml - .travis.yml
- README.md - README.md
- properdocs.yml - mkdocs.yml
- noxfile.py - noxfile.py
jobs: jobs:
+22 -41
View File
@@ -40,6 +40,28 @@ additionalProperties: false
description: cibuildwheel's settings. description: cibuildwheel's settings.
type: object type: object
properties: properties:
inherit:
type: object
additionalProperties: false
properties:
audit-command: {"$ref": "#/$defs/inherit"}
audit-requires: {"$ref": "#/$defs/inherit"}
before-all: {"$ref": "#/$defs/inherit"}
before-build: {"$ref": "#/$defs/inherit"}
xbuild-tools: {"$ref": "#/$defs/inherit"}
xbuild-files: {"$ref": "#/$defs/inherit"}
before-test: {"$ref": "#/$defs/inherit"}
config-settings: {"$ref": "#/$defs/inherit"}
container-engine: {"$ref": "#/$defs/inherit"}
environment: {"$ref": "#/$defs/inherit"}
environment-pass: {"$ref": "#/$defs/inherit"}
repair-wheel-command: {"$ref": "#/$defs/inherit"}
test-command: {"$ref": "#/$defs/inherit"}
test-extras: {"$ref": "#/$defs/inherit"}
test-sources: {"$ref": "#/$defs/inherit"}
test-requires: {"$ref": "#/$defs/inherit"}
test-environment: {"$ref": "#/$defs/inherit"}
test-runtime: {"$ref": "#/$defs/inherit"}
audit-command: audit-command:
description: Execute a shell command to audit each wheel after it is repaired. Use {wheel} for each wheel path, or {abi3_wheel} to only audit abi3 wheels. description: Execute a shell command to audit each wheel after it is repaired. Use {wheel} for each wheel path, or {abi3_wheel} to only audit abi3 wheels.
type: string_array type: string_array
@@ -315,28 +337,6 @@ items:
additionalProperties: false additionalProperties: false
properties: properties:
select: {} select: {}
inherit:
type: object
additionalProperties: false
properties:
audit-command: {"$ref": "#/$defs/inherit"}
audit-requires: {"$ref": "#/$defs/inherit"}
before-all: {"$ref": "#/$defs/inherit"}
before-build: {"$ref": "#/$defs/inherit"}
xbuild-tools: {"$ref": "#/$defs/inherit"}
xbuild-files: {"$ref": "#/$defs/inherit"}
before-test: {"$ref": "#/$defs/inherit"}
config-settings: {"$ref": "#/$defs/inherit"}
container-engine: {"$ref": "#/$defs/inherit"}
environment: {"$ref": "#/$defs/inherit"}
environment-pass: {"$ref": "#/$defs/inherit"}
repair-wheel-command: {"$ref": "#/$defs/inherit"}
test-command: {"$ref": "#/$defs/inherit"}
test-extras: {"$ref": "#/$defs/inherit"}
test-sources: {"$ref": "#/$defs/inherit"}
test-requires: {"$ref": "#/$defs/inherit"}
test-environment: {"$ref": "#/$defs/inherit"}
test-runtime: {"$ref": "#/$defs/inherit"}
""" """
) )
@@ -393,25 +393,6 @@ for os_name, command in [
del oses["linux"]["properties"]["dependency-versions"] del oses["linux"]["properties"]["dependency-versions"]
oses["pyodide"]["properties"]["build-frontend"] = {
**schema["properties"]["build-frontend"],
"default": "pyodide-build",
"description": 'On the pyodide platform, the build frontend must be "pyodide-build"',
"oneOf": [
{"enum": ["pyodide-build"]},
{"type": "string", "pattern": "^pyodide-build; ?args:"},
{
"type": "object",
"additionalProperties": False,
"required": ["name"],
"properties": {
"name": {"enum": ["pyodide-build"]},
"args": {"type": "array", "items": {"type": "string"}},
},
},
],
}
schema["properties"]["overrides"] = overrides schema["properties"]["overrides"] = overrides
schema["properties"] |= oses schema["properties"] |= oses
+43 -91
View File
@@ -9,7 +9,6 @@
import configparser import configparser
import dataclasses import dataclasses
from functools import cache
from pathlib import Path from pathlib import Path
import requests import requests
@@ -34,7 +33,7 @@ class PyPAImage(Image):
super().__init__(manylinux_version, platforms, image_name, tag, True) super().__init__(manylinux_version, platforms, image_name, tag, True)
IMAGES = [ images = [
# manylinux2014 images # manylinux2014 images
PyPAImage( PyPAImage(
"manylinux2014", "manylinux2014",
@@ -89,71 +88,49 @@ IMAGES = [
), ),
] ]
config = configparser.ConfigParser()
@cache for image in images:
def quay_lookup(image_name: str, tag_name: str) -> tuple[str, str]: # get the tag name whose digest matches 'latest'
_, _, repository_name = image_name.partition("/") if image.tag is not None:
if tag_name == "latest": # image has been pinned, do not update
url = f"https://quay.io/api/v1/repository/{repository_name}?includeTags=true" tag_name = image.tag
else: elif image.image_name.startswith("quay.io/"):
url = f"https://quay.io/api/v1/repository/{repository_name}/tag?specificTag={tag_name}" _, _, repository_name = image.image_name.partition("/")
response = requests.get(url) response = requests.get(
response.raise_for_status() f"https://quay.io/api/v1/repository/{repository_name}?includeTags=true"
info = response.json()
if tag_name == "latest":
tags_dict = info["tags"]
tag_info = tags_dict.pop(tag_name)
# find the tag whose manifest matches 'latest'
tag_name, digest = next(
(name, info["manifest_digest"])
for (name, info) in tags_dict.items()
if info["manifest_digest"] == tag_info["manifest_digest"]
) )
else: response.raise_for_status()
tags_list = info["tags"] repo_info = response.json()
tag_info = next(tag for tag in tags_list if tag["name"] == tag_name) tags_dict = repo_info["tags"]
digest = tag_info["manifest_digest"]
return tag_name, digest latest_tag = tags_dict.pop("latest")
# find the tag whose manifest matches 'latest'
tag_name = next(
@cache name
def ghcr_lookup(image_name: str, tag_name: str) -> tuple[str, str]: for (name, info) in tags_dict.items()
repository = image_name[8:] if info["manifest_digest"] == latest_tag["manifest_digest"]
response = requests.get( )
"https://ghcr.io/token", params={"scope": f"repository:{repository}:pull"} elif image.image_name.startswith("ghcr.io/"):
) repository = image.image_name[8:]
response.raise_for_status() response = requests.get(
token = response.json()["token"] "https://ghcr.io/token", params={"scope": f"repository:{repository}:pull"}
if tag_name == "latest": )
response.raise_for_status()
token = response.json()["token"]
response = requests.get( response = requests.get(
f"https://ghcr.io/v2/{repository}/tags/list", f"https://ghcr.io/v2/{repository}/tags/list",
headers={"Authorization": f"Bearer {token}"}, headers={"Authorization": f"Bearer {token}"},
) )
response.raise_for_status() response.raise_for_status()
info = response.json() ghcr_tags = [(Version(tag), tag) for tag in response.json()["tags"] if tag != "latest"]
ghcr_tags = [(Version(tag), tag) for tag in info["tags"] if tag != "latest"]
ghcr_tags.sort(reverse=True) ghcr_tags.sort(reverse=True)
tag_name = ghcr_tags[0][1] tag_name = ghcr_tags[0][1]
else:
response = requests.get(f"https://hub.docker.com/v2/repositories/{image.image_name}/tags")
response.raise_for_status()
tags = response.json()["results"]
response = requests.head(
f"https://ghcr.io/v2/{repository}/manifests/{tag_name}",
headers={
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.oci.artifact.manifest.v1+json",
},
)
response.raise_for_status()
digest = response.headers["Docker-Content-Digest"]
return tag_name, digest
@cache
def dockerhub_lookup(image_name: str, tag_name: str) -> tuple[str, str]:
response = requests.get(f"https://hub.docker.com/v2/repositories/{image_name}/tags")
response.raise_for_status()
tags = response.json()["results"]
if tag_name == "latest":
latest_tag = next(tag for tag in tags if tag["name"] == "latest") latest_tag = next(tag for tag in tags if tag["name"] == "latest")
# i don't know what it would mean to have multiple images per tag # i don't know what it would mean to have multiple images per tag
assert len(latest_tag["images"]) == 1 assert len(latest_tag["images"]) == 1
@@ -162,40 +139,15 @@ def dockerhub_lookup(image_name: str, tag_name: str) -> tuple[str, str]:
pinned_tag = next( pinned_tag = next(
tag for tag in tags if tag != latest_tag and tag["images"][0]["digest"] == digest tag for tag in tags if tag != latest_tag and tag["images"][0]["digest"] == digest
) )
else: tag_name = pinned_tag["name"]
pinned_tag = next(tag for tag in tags if tag["name"] == tag_name)
digest = pinned_tag["images"][0]["digest"]
tag_name = pinned_tag["name"]
return tag_name, digest
for platform in image.platforms:
if not config.has_section(platform):
config[platform] = {}
suffix = ""
if image.use_platform_suffix:
suffix = f"_{platform.removeprefix('pypy_')}"
config[platform][image.manylinux_version] = f"{image.image_name}{suffix}:{tag_name}"
def main() -> None: with open(RESOURCES / "pinned_docker_images.cfg", "w") as f:
config = configparser.ConfigParser() config.write(f)
for image in IMAGES:
# get the tag name whose digest matches 'latest'
# if image has been pinned, do not update
search_tag = image.tag or "latest"
if image.image_name.startswith("quay.io/"):
lookup = quay_lookup
elif image.image_name.startswith("ghcr.io/"):
lookup = ghcr_lookup
else:
lookup = dockerhub_lookup
tag_name, digest = lookup(image.image_name, search_tag)
for platform in image.platforms:
if not config.has_section(platform):
config[platform] = {}
image_name = image.image_name
if image.use_platform_suffix:
image_name = f"{image_name}_{platform.removeprefix('pypy_')}"
_, digest = lookup(image_name, tag_name)
assert digest.startswith("sha256:")
config[platform][image.manylinux_version] = f"{image_name}@{digest} # {tag_name}"
with open(RESOURCES / "pinned_docker_images.cfg", "w") as f:
config.write(f)
if __name__ == "__main__":
main()
+1 -1
View File
@@ -1 +1 @@
__version__ = "4.1.1" __version__ = "4.1.0"
+1 -6
View File
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
from cibuildwheel.typing import PathOrStr from cibuildwheel.typing import PathOrStr
BuildFrontendName = Literal["pip", "build", "build[uv]", "uv", "pyodide-build"] BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"]
@dataclasses.dataclass(frozen=True) @dataclasses.dataclass(frozen=True)
@@ -46,11 +46,6 @@ class BuildFrontendConfig:
def _get_verbosity_flags(level: int, frontend: BuildFrontendName) -> list[str]: def _get_verbosity_flags(level: int, frontend: BuildFrontendName) -> list[str]:
if frontend == "pyodide-build":
if level > 0:
return ["-" + min(level, 2) * "v"]
return []
if level < 0: if level < 0:
return ["-" + -level * "q"] return ["-" + -level * "q"]
+123 -61
View File
@@ -43,14 +43,20 @@ from packaging.specifiers import SpecifierSet
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture from cibuildwheel.architecture import Architecture
from cibuildwheel.environment import EnvironmentParseError, ParsedEnvironment, parse_environment from cibuildwheel.environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from cibuildwheel.frontend import BuildFrontendConfig, BuildFrontendName from cibuildwheel.frontend import BuildFrontendConfig
from cibuildwheel.logger import log from cibuildwheel.logger import log
from cibuildwheel.oci_container import OCIContainerEngineConfig from cibuildwheel.oci_container import OCIContainerEngineConfig
from cibuildwheel.projectfiles import get_requires_python_str, resolve_dependency_groups from cibuildwheel.projectfiles import get_requires_python_str, resolve_dependency_groups
from cibuildwheel.selector import BuildSelector, EnableGroup, TestSelector, selector_matches from cibuildwheel.selector import BuildSelector, EnableGroup, TestSelector, selector_matches
from cibuildwheel.typing import PLATFORMS, PlatformName from cibuildwheel.typing import PLATFORMS, PlatformName
from cibuildwheel.util import resources from cibuildwheel.util import resources
from cibuildwheel.util.helpers import format_safe, parse_key_value_string, strtobool, unwrap from cibuildwheel.util.helpers import (
format_safe,
parse_arbitrary_key_value_string,
parse_key_value_string,
strtobool,
unwrap,
)
from cibuildwheel.util.packaging import DependencyConstraints from cibuildwheel.util.packaging import DependencyConstraints
TYPE_CHECKING = False TYPE_CHECKING = False
@@ -436,6 +442,28 @@ def _stringify_setting(
return setting return setting
def parse_inherit(config: str | dict[str, str] | None) -> dict[str, InheritRule]:
inherit_dict: dict[str, str]
if config is None:
return {}
if isinstance(config, str):
parsed = parse_arbitrary_key_value_string(config, default_value="append")
inherit_dict = {k: "".join(v) for k, v in parsed.items()}
elif isinstance(config, dict):
inherit_dict = config
else:
msg = "'inherit' must be a string or a table"
raise OptionsReaderError(msg)
if not all(v in {"none", "append", "prepend"} for v in inherit_dict.values()):
msg = "'inherit' must contain only {'none', 'append', 'prepend'} values"
raise OptionsReaderError(msg)
return {k: InheritRule[v.upper()] for k, v in inherit_dict.items()}
class OptionsReader: class OptionsReader:
""" """
Gets options from the environment, config or defaults, optionally scoped Gets options from the environment, config or defaults, optionally scoped
@@ -484,45 +512,18 @@ class OptionsReader:
self._validate_platform_option(option_name) self._validate_platform_option(option_name)
self.config_options = config_options self.config_options = config_options
self.config_options_inherit = parse_inherit(config_options.get("inherit"))
self.config_platform_options = config_platform_options self.config_platform_options = config_platform_options
self.config_platform_options_inherit = parse_inherit(config_platform_options.get("inherit"))
self.overrides: list[Override] = []
self.current_identifier: str | None = None self.current_identifier: str | None = None
config_overrides = self.config_options.get("overrides")
if config_overrides is not None:
if not isinstance(config_overrides, list):
msg = "'tool.cibuildwheel.overrides' must be a list"
raise OptionsReaderError(msg)
for config_override in config_overrides:
select = config_override.pop("select", None)
if not select:
msg = "'select' must be set in an override"
raise OptionsReaderError(msg)
if isinstance(select, list):
select = " ".join(select)
inherit = config_override.pop("inherit", {})
if not isinstance(inherit, dict) or not all(
i in {"none", "append", "prepend"} for i in inherit.values()
):
msg = "'inherit' must be a dict containing only {'none', 'append', 'prepend'} values"
raise OptionsReaderError(msg)
inherit_enum = {k: InheritRule[v.upper()] for k, v in inherit.items()}
self.overrides.append(Override(select, config_override, inherit_enum))
def _validate_global_option(self, name: str) -> None: def _validate_global_option(self, name: str) -> None:
""" """
Raises an error if an option with this name is not allowed in the Raises an error if an option with this name is not allowed in the
[tool.cibuildwheel] section of a config file. [tool.cibuildwheel] section of a config file.
""" """
allowed_option_names = self.default_options.keys() | PLATFORMS | {"overrides"} allowed_option_names = self.default_options.keys() | PLATFORMS | {"inherit", "overrides"}
if name not in allowed_option_names: if name not in allowed_option_names:
msg = f"Option {name!r} not supported in a config file." msg = f"Option {name!r} not supported in a config file."
@@ -541,7 +542,9 @@ class OptionsReader:
msg = f"{name!r} is not allowed in {disallowed_platform_options}" msg = f"{name!r} is not allowed in {disallowed_platform_options}"
raise OptionsReaderError(msg) raise OptionsReaderError(msg)
allowed_option_names = self.default_options.keys() | self.default_platform_options.keys() allowed_option_names = (
self.default_options.keys() | self.default_platform_options.keys() | {"inherit"}
)
if name not in allowed_option_names: if name not in allowed_option_names:
msg = f"Option {name!r} not supported in the {self.platform!r} section" msg = f"Option {name!r} not supported in the {self.platform!r} section"
@@ -562,6 +565,56 @@ class OptionsReader:
return global_options, platform_options return global_options, platform_options
@functools.cached_property
def overrides(self) -> list[Override]:
config_overrides = self.config_options.get("overrides")
overrides: list[Override] = []
if config_overrides is not None:
if not isinstance(config_overrides, list):
msg = "'tool.cibuildwheel.overrides' must be a list"
raise OptionsReaderError(msg)
for config_override in config_overrides:
select = config_override.pop("select", None)
if not select:
msg = "'select' must be set in an override"
raise OptionsReaderError(msg)
if isinstance(select, list):
select = " ".join(select)
inherit = config_override.pop("inherit", {})
overrides.append(Override(select, config_override, parse_inherit(inherit)))
return overrides
@functools.cached_property
def env_inherit(self) -> dict[str, InheritRule]:
env_inherit_str = self.env.get("CIBW_INHERIT", "")
try:
return parse_inherit(env_inherit_str)
except OptionsReaderError as e:
msg = f"Failed to parse CIBW_INHERIT environment variable. {e}"
raise errors.ConfigurationError(msg) from e
@functools.cached_property
def env_platform_inherit(self) -> dict[str, InheritRule]:
env_inherit = self.env_inherit
# find the rules which have -{platform} on the end of their key,
# remove the platform suffix from the key and return the resulting
# rule.
platform_suffix = f"-{self.platform}"
return {
key.removesuffix(platform_suffix): value
for key, value in env_inherit.items()
if key.endswith(platform_suffix)
}
@property @property
def active_config_overrides(self) -> list[Override]: def active_config_overrides(self) -> list[Override]:
if self.current_identifier is None: if self.current_identifier is None:
@@ -585,7 +638,7 @@ class OptionsReader:
env_plat: bool = True, env_plat: bool = True,
option_format: OptionFormat | None = None, option_format: OptionFormat | None = None,
ignore_empty: bool = False, ignore_empty: bool = False,
env_rule: InheritRule = InheritRule.NONE, default_env_rule: InheritRule = InheritRule.NONE,
) -> str: ) -> str:
""" """
Get and return the value for the named option from environment, Get and return the value for the named option from environment,
@@ -609,16 +662,37 @@ class OptionsReader:
# get the option from the default, then the config file, then finally the environment. # get the option from the default, then the config file, then finally the environment.
# platform-specific options are preferred, if they're allowed. # platform-specific options are preferred, if they're allowed.
return _resolve_cascade( return _resolve_cascade(
(self.default_options.get(name), InheritRule.NONE), (
(self.default_platform_options.get(name), InheritRule.NONE), self.default_options.get(name),
(self.config_options.get(name), InheritRule.NONE), InheritRule.NONE,
(self.config_platform_options.get(name), InheritRule.NONE), ),
(
self.default_platform_options.get(name),
InheritRule.NONE,
),
(
self.config_options.get(name),
self.config_options_inherit.get(name, InheritRule.NONE),
),
(
self.config_platform_options.get(name),
self.config_platform_options_inherit.get(name, InheritRule.NONE),
),
*[ *[
(o.options.get(name), o.inherit.get(name, InheritRule.NONE)) (
o.options.get(name),
o.inherit.get(name, InheritRule.NONE),
)
for o in self.active_config_overrides for o in self.active_config_overrides
], ],
(self.env.get(envvar), env_rule), (
(self.env.get(plat_envvar) if env_plat else None, env_rule), self.env.get(envvar),
self.env_inherit.get(name, default_env_rule),
),
(
self.env.get(plat_envvar) if env_plat else None,
self.env_platform_inherit.get(name, default_env_rule),
),
ignore_empty=ignore_empty, ignore_empty=ignore_empty,
option_format=option_format, option_format=option_format,
) )
@@ -691,7 +765,10 @@ class Options:
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0")) allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
enable_groups = self.reader.get( enable_groups = self.reader.get(
"enable", env_plat=False, option_format=ListFormat(sep=" "), env_rule=InheritRule.APPEND "enable",
env_plat=False,
option_format=ListFormat(sep=" "),
default_env_rule=InheritRule.APPEND,
) )
try: try:
enable = { enable = {
@@ -797,12 +874,11 @@ class Options:
if xbuild_tools == ["\u0000"]: if xbuild_tools == ["\u0000"]:
xbuild_tools = None xbuild_tools = None
xbuild_files = parse_key_value_string( xbuild_files = parse_arbitrary_key_value_string(
self.reader.get( self.reader.get(
"xbuild-files", "xbuild-files",
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False), option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
), ),
kw_arg_names=["*"],
) )
test_sources = shlex.split( test_sources = shlex.split(
@@ -821,6 +897,7 @@ class Options:
test_runtime_str = self.reader.get( test_runtime_str = self.reader.get(
"test-runtime", "test-runtime",
env_plat=False,
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False), option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
) )
if not test_runtime_str: if not test_runtime_str:
@@ -850,11 +927,8 @@ class Options:
env_plat=False, env_plat=False,
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False), option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
) )
default_frontend: BuildFrontendName = (
"pyodide-build" if self.platform == "pyodide" else "build"
)
if not build_frontend_str or build_frontend_str == "default": if not build_frontend_str or build_frontend_str == "default":
build_frontend = BuildFrontendConfig(default_frontend) build_frontend = BuildFrontendConfig("build")
else: else:
try: try:
build_frontend = BuildFrontendConfig.from_config_string(build_frontend_str) build_frontend = BuildFrontendConfig.from_config_string(build_frontend_str)
@@ -862,18 +936,6 @@ class Options:
msg = f"Failed to parse build frontend. {e}" msg = f"Failed to parse build frontend. {e}"
raise errors.ConfigurationError(msg) from e raise errors.ConfigurationError(msg) from e
if self.platform == "pyodide" and build_frontend.name != "pyodide-build":
# pip and uv could become an error, eventually. build -> pyodide-build is
# probably fine to keep as a warning
log.warning(
f"The pyodide platform ignores the {build_frontend.name!r} build "
"frontend; using 'pyodide-build' instead"
)
build_frontend = BuildFrontendConfig("pyodide-build", build_frontend.args)
if self.platform != "pyodide" and build_frontend.name == "pyodide-build":
msg = "The 'pyodide-build' build frontend is only supported on the pyodide platform"
raise errors.ConfigurationError(msg)
try: try:
environment = parse_environment(environment_config) environment = parse_environment(environment_config)
except (EnvironmentParseError, ValueError) as e: except (EnvironmentParseError, ValueError) as e:
@@ -1138,6 +1200,6 @@ def _get_pinned_container_images() -> Mapping[str, Mapping[str, str]]:
'pypy_x86_64': {'manylinux2010': '...' } 'pypy_x86_64': {'manylinux2010': '...' }
... } ... }
""" """
all_pinned_images = configparser.ConfigParser(inline_comment_prefixes="#") all_pinned_images = configparser.ConfigParser()
all_pinned_images.read(resources.PINNED_DOCKER_IMAGES) all_pinned_images.read(resources.PINNED_DOCKER_IMAGES)
return all_pinned_images return all_pinned_images
+7 -5
View File
@@ -223,6 +223,10 @@ def setup_target_python(config: PythonConfiguration, build_path: Path) -> Path:
python_dir.mkdir() python_dir.mkdir()
shutil.unpack_archive(python_tgz, python_dir) shutil.unpack_archive(python_tgz, python_dir)
# Patch a testbed bug. This code and the patch file can both be removed once we've
# updated to Python versions that include the fix.
call("patch", "-p1", "-i", RESOURCES_ANDROID / "android.patch", cwd=python_dir)
# Work around https://github.com/python/cpython/issues/138800. This can be removed # Work around https://github.com/python/cpython/issues/138800. This can be removed
# once we've updated to Python versions that include the fix. # once we've updated to Python versions that include the fix.
pc_path = python_dir / f"prefix/lib/pkgconfig/python-{config.version}.pc" pc_path = python_dir / f"prefix/lib/pkgconfig/python-{config.version}.pc"
@@ -310,9 +314,7 @@ def setup_env(
"wheel", "wheel",
parse_config_settings( parse_config_settings(
prepare_config_settings( prepare_config_settings(
build_options.config_settings, build_options.config_settings, project=".", package=build_options.package_dir
project=Path.cwd(),
package=build_options.package_dir,
) )
), ),
) )
@@ -602,7 +604,7 @@ def build_wheel(state: BuildState) -> Path:
state.options.build_verbosity, state.options.build_verbosity,
prepare_config_settings( prepare_config_settings(
state.options.config_settings, state.options.config_settings,
project=Path.cwd(), project=".",
package=state.options.package_dir, package=state.options.package_dir,
), ),
), ),
@@ -623,7 +625,7 @@ def build_wheel(state: BuildState) -> Path:
state.options.build_verbosity, state.options.build_verbosity,
prepare_config_settings( prepare_config_settings(
state.options.config_settings, state.options.config_settings,
project=Path.cwd(), project=".",
package=state.options.package_dir, package=state.options.package_dir,
), ),
), ),
+1 -7
View File
@@ -463,9 +463,6 @@ def setup_python(
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -559,7 +556,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_verbosity, build_options.build_verbosity,
prepare_config_settings( prepare_config_settings(
build_options.config_settings, build_options.config_settings,
project=Path.cwd(), project=".",
package=build_options.package_dir, package=build_options.package_dir,
), ),
) )
@@ -591,9 +588,6 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags, *extra_flags,
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
-3
View File
@@ -360,9 +360,6 @@ def build_in_container(
], ],
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
+9 -16
View File
@@ -215,19 +215,18 @@ def install_cpython(_tmp: Path, version: str, url: str, free_threading: bool, sh
def install_pypy(tmp: Path, url: str, sha256: str) -> Path: def install_pypy(tmp: Path, url: str, sha256: str) -> Path:
pypy_archive = url.rsplit("/", 1)[-1] pypy_tar_bz2 = url.rsplit("/", 1)[-1]
# PyPy ships .tar.bz2 for some platforms and .tar.gz for others. extension = ".tar.bz2"
extension = ".tar.bz2" if pypy_archive.endswith(".tar.bz2") else ".tar.gz" assert pypy_tar_bz2.endswith(extension)
assert pypy_archive.endswith(extension) installation_path = CIBW_CACHE_PATH / pypy_tar_bz2[: -len(extension)]
installation_path = CIBW_CACHE_PATH / pypy_archive[: -len(extension)]
with FileLock(str(installation_path) + ".lock"): with FileLock(str(installation_path) + ".lock"):
if not installation_path.exists(): if not installation_path.exists():
downloaded_archive = tmp / pypy_archive downloaded_tar_bz2 = tmp / pypy_tar_bz2
download(url, downloaded_archive, sha256=sha256) download(url, downloaded_tar_bz2, sha256=sha256)
installation_path.parent.mkdir(parents=True, exist_ok=True) installation_path.parent.mkdir(parents=True, exist_ok=True)
with remove_on_error(installation_path): with remove_on_error(installation_path):
call("tar", "-C", installation_path.parent, "-xf", downloaded_archive) call("tar", "-C", installation_path.parent, "-xf", downloaded_tar_bz2)
downloaded_archive.unlink() downloaded_tar_bz2.unlink()
return installation_path / "bin" / "pypy3" return installation_path / "bin" / "pypy3"
@@ -450,9 +449,6 @@ def setup_python(
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -538,7 +534,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_verbosity, build_options.build_verbosity,
prepare_config_settings( prepare_config_settings(
build_options.config_settings, build_options.config_settings,
project=Path.cwd(), project=".",
package=build_options.package_dir, package=build_options.package_dir,
), ),
) )
@@ -589,9 +585,6 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags, *extra_flags,
env=build_env, env=build_env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
+5 -1
View File
@@ -426,6 +426,10 @@ 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
if build_frontend.name == "pip":
msg = "The pyodide platform doesn't support pip frontend"
raise errors.FatalError(msg)
log.build_start(config.identifier) log.build_start(config.identifier)
identifier_tmp_dir = tmp_path / config.identifier identifier_tmp_dir = tmp_path / config.identifier
@@ -489,7 +493,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_verbosity, build_options.build_verbosity,
prepare_config_settings( prepare_config_settings(
build_options.config_settings, build_options.config_settings,
project=Path.cwd(), project=".",
package=build_options.package_dir, package=build_options.package_dir,
), ),
) )
+1 -7
View File
@@ -401,9 +401,6 @@ def setup_python(
*constraint_flags(dependency_constraint), *constraint_flags(dependency_constraint),
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -492,7 +489,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_verbosity, build_options.build_verbosity,
prepare_config_settings( prepare_config_settings(
build_options.config_settings, build_options.config_settings,
project=Path.cwd(), project=".",
package=options.globals.package_dir, package=options.globals.package_dir,
), ),
) )
@@ -542,9 +539,6 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags, *extra_flags,
env=env, env=env,
) )
case "pyodide-build":
msg = "The 'pyodide-build' build frontend is not supported on this platform"
raise errors.FatalError(msg)
case _: case _:
assert_never(build_frontend) assert_never(build_frontend)
@@ -0,0 +1,11 @@
--- a/android.py
+++ b/android.py
@@ -1021,7 +1021,7 @@ def main():
context = parse_args()
# Set the CROSS_BUILD_DIR if an argument was provided
- if context.cross_build_dir:
+ if getattr(context, "cross_build_dir", None):
global CROSS_BUILD_DIR
CROSS_BUILD_DIR = context.cross_build_dir.resolve()
+50 -50
View File
@@ -153,27 +153,27 @@ 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", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" }, { identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" },
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" }, { identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" },
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" }, { identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg", sha256 = "8373e58da4ea146b3eb1c1f9834f19a319440b6b679b06050b1f9ee3237aa8e4" },
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.14/python-3.13.14-macos11.pkg", sha256 = "8e58affb218c155a1dfdc27b291f817129669f8760e7a297adb2e4439ba5d2e8" }, { identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.13/python-3.13.13-macos11.pkg", sha256 = "a909cb655af5db67d5a90b3603437a1d58bec3446d624e4034e278ac62023cc9" },
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.14/python-3.13.14-macos11.pkg", sha256 = "8e58affb218c155a1dfdc27b291f817129669f8760e7a297adb2e4439ba5d2e8" }, { identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.13/python-3.13.13-macos11.pkg", sha256 = "a909cb655af5db67d5a90b3603437a1d58bec3446d624e4034e278ac62023cc9" },
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.14/python-3.13.14-macos11.pkg", sha256 = "8e58affb218c155a1dfdc27b291f817129669f8760e7a297adb2e4439ba5d2e8" }, { identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.13/python-3.13.13-macos11.pkg", sha256 = "a909cb655af5db67d5a90b3603437a1d58bec3446d624e4034e278ac62023cc9" },
{ identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314t-macosx_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314t-macosx_arm64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-macos11.pkg", sha256 = "d3c9fff52214847e4fab03e9eaf53dd2a8e51e3534aa0b61f201b749f86bef28" }, { identifier = "cp314t-macosx_universal2", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-macos11.pkg", sha256 = "b28a8dc33c456dd06c97024697d63ca916cfb494594c06fa3e4ef4d41fa82335" },
{ identifier = "cp315-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "cp315-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "cp315-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "cp315t-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315t-macosx_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "cp315t-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315t-macosx_arm64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "cp315t-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-macos11.pkg", sha256 = "6f1ed07cc92ed6e694b38b29d929a4e55190532fddb3828afe68d07cd4bf4aff" }, { identifier = "cp315t-macosx_universal2", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-macos11.pkg", sha256 = "29b5c95f255f846f77e1c119146836445f929de1392a3ae9ef24f559e1345418" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.gz", sha256 = "7ea762a1b0af7545a74cd4260bb3fd2812813deffef2ef8d2fddd5e03fa63ef1" }, { identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2", sha256 = "fda015431621e7e5aa16359d114f2c45a77ed936992c1efff86302e768a6b21c" },
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.gz", sha256 = "b09ce3a865c1c0f4e58c0ee4f70511f1b27dfc1f7148f4b6060cfdfd581c9e82" }, { identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2", sha256 = "88f824e7a2d676440d09bc90fc959ae0fd3557d7e2f14bfbbe53d41d159a47fe" },
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.gz", sha256 = "63f9d30cdd9e47cfe279be941975ac3d24e46c79756cd1d1bd2c551c27d8b32c" }, { identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_x86_64.tar.bz2", sha256 = "2c5e5c2a33ac882551d7f28b98d19d486b8995aa50824a73b4edcc6aeec35c63" },
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.gz", sha256 = "72a74cf645e43608f7d88831581fb0f8e1f963fb38f0793bacd37d5018a9aeb8" }, { identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-macos_arm64.tar.bz2", sha256 = "3db8a03fc496164801646844d7f3b12baa0adb3ad9a0b7cb124521bc2e168a36" },
{ identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-macos_x86_64.tar.gz", sha256 = "798279b0f233893ae22754290aedf35a1aea1ec9013a8ad8110f166d85944c91" }, { identifier = "pp311-macosx_x86_64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-macos_x86_64.tar.bz2", sha256 = "c95363c4e87235d11a6cec8128239c291b1eb67a752778fbcfe029a71da82b5e" },
{ identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-macos_arm64.tar.gz", sha256 = "f837b3c203d60d7e25a31e267671a07ba0c9b9ac8081ad225571fb06fccf1b7b" }, { identifier = "pp311-macosx_arm64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-macos_arm64.tar.bz2", sha256 = "4747b3aceba4c1c6104cddc0fe5ea302101d32955f0957347b9ecc4fbd7aed05" },
{ 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", sha256 = "10b0721d52397f0cc85f038900318da2203711cbcfae7899e3faed49d3dc6221" }, { 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", sha256 = "10b0721d52397f0cc85f038900318da2203711cbcfae7899e3faed49d3dc6221" },
{ identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.3/graalpy-25.0.3-macos-aarch64.tar.gz", sha256 = "387d9f5b376860842bea4d55aae5820974f3f3b68fc36c77ae863a061a888857" }, { identifier = "gp312_250-macosx_arm64", version = "3.12", url = "https://github.com/oracle/graalpython/releases/download/graal-25.0.3/graalpy-25.0.3-macos-aarch64.tar.gz", sha256 = "387d9f5b376860842bea4d55aae5820974f3f3b68fc36c77ae863a061a888857" },
] ]
@@ -188,25 +188,25 @@ 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.14" }, { identifier = "cp313-win32", version = "3.13.13" },
{ identifier = "cp313-win_amd64", version = "3.13.14" }, { identifier = "cp313-win_amd64", version = "3.13.13" },
{ identifier = "cp314-win32", version = "3.14.6" }, { identifier = "cp314-win32", version = "3.14.5" },
{ identifier = "cp314t-win32", version = "3.14.6" }, { identifier = "cp314t-win32", version = "3.14.5" },
{ identifier = "cp314-win_amd64", version = "3.14.6" }, { identifier = "cp314-win_amd64", version = "3.14.5" },
{ identifier = "cp314t-win_amd64", version = "3.14.6" }, { identifier = "cp314t-win_amd64", version = "3.14.5" },
{ identifier = "cp315-win32", version = "3.15.0-b4" }, { identifier = "cp315-win32", version = "3.15.0-b2" },
{ identifier = "cp315t-win32", version = "3.15.0-b4" }, { identifier = "cp315t-win32", version = "3.15.0-b2" },
{ identifier = "cp315-win_amd64", version = "3.15.0-b4" }, { identifier = "cp315-win_amd64", version = "3.15.0-b2" },
{ identifier = "cp315t-win_amd64", version = "3.15.0-b4" }, { identifier = "cp315t-win_amd64", version = "3.15.0-b2" },
{ 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.14" }, { identifier = "cp313-win_arm64", version = "3.13.13" },
{ identifier = "cp314-win_arm64", version = "3.14.6" }, { identifier = "cp314-win_arm64", version = "3.14.5" },
{ identifier = "cp314t-win_arm64", version = "3.14.6" }, { identifier = "cp314t-win_arm64", version = "3.14.5" },
{ identifier = "cp315-win_arm64", version = "3.15.0-b4" }, { identifier = "cp315-win_arm64", version = "3.15.0-b2" },
{ identifier = "cp315t-win_arm64", version = "3.15.0-b4" }, { identifier = "cp315t-win_arm64", version = "3.15.0-b2" },
{ identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip", sha256 = "06ec12a5e964dc0ad33e6f380185a4d295178dce6d6df512f508e7aee00a1323" }, { identifier = "pp39-win_amd64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip", sha256 = "06ec12a5e964dc0ad33e6f380185a4d295178dce6d6df512f508e7aee00a1323" },
{ identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip", sha256 = "c0d07bba6c8fb4e5804f4a8b3f8ef07cc3d89f6ad1db42a45ffb9be60bbb7cc2" }, { identifier = "pp310-win_amd64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.19-win64.zip", sha256 = "c0d07bba6c8fb4e5804f4a8b3f8ef07cc3d89f6ad1db42a45ffb9be60bbb7cc2" },
{ identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-win64.zip", sha256 = "948b8ea58dea5b9917210fe4afd242c788fbfaba1c3f1a25e696a404f703389a" }, { identifier = "pp311-win_amd64", version = "3.11", url = "https://downloads.python.org/pypy/pypy3.11-v7.3.23-win64.zip", sha256 = "948b8ea58dea5b9917210fe4afd242c788fbfaba1c3f1a25e696a404f703389a" },
@@ -217,28 +217,28 @@ python_configurations = [
python_configurations = [ python_configurations = [
{ identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22", sha256 = "0c2e7db42efa5d1dac38b50f8b3d659a1e3885d0a233494831b8206281307d52" }, { identifier = "cp312-pyodide_wasm32", version = "3.12", default_pyodide_version = "0.27.7", node_version = "v22", sha256 = "0c2e7db42efa5d1dac38b50f8b3d659a1e3885d0a233494831b8206281307d52" },
{ identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.4", node_version = "v22", sha256 = "a29fc4a076408a18fc29eb4b280f80c6dddc95c19514c874c29e590d0931c02a" }, { identifier = "cp313-pyodide_wasm32", version = "3.13", default_pyodide_version = "0.29.4", node_version = "v22", sha256 = "a29fc4a076408a18fc29eb4b280f80c6dddc95c19514c874c29e590d0931c02a" },
{ identifier = "cp314-pyodide_wasm32", version = "3.14", default_pyodide_version = "314.0.2", node_version = "v24", sha256 = "01ab1b229bf2031603bf20ad4ceb9c1059ba680b26df7bda2db4748906dfd78a" }, { identifier = "cp314-pyodide_wasm32", version = "3.14", default_pyodide_version = "314.0.0", node_version = "v24", sha256 = "6e76cf18251bd7d046bdb7ef35c9f938c8e995f10d88397497ca4b7020f27ba6" },
] ]
[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.14/python-3.13.14-aarch64-linux-android.tar.gz", sha256 = "2541c4fa77b6543504c97fa90a71c745225b5800fe25bc8c73a6516b594d0cbc" }, { identifier = "cp313-android_arm64_v8a", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.13/python-3.13.13-aarch64-linux-android.tar.gz", sha256 = "a21250c246b36eb704be096be51e40ab24cafa3ae1d7ca4c396e6bf780cf87cf" },
{ identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.14/python-3.13.14-x86_64-linux-android.tar.gz", sha256 = "9d96f7e077677b6651b2e756034ed41ab4479f5f8bf3168a814f458bc2ac137e" }, { identifier = "cp313-android_x86_64", version = "3.13", url = "https://repo.maven.apache.org/maven2/com/chaquo/python/python/3.13.13/python-3.13.13-x86_64-linux-android.tar.gz", sha256 = "b021b76df2c8d64e41c76d18a2d91f27652356bd932c06f9076bac1b664c0e37" },
{ identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-aarch64-linux-android.tar.gz", sha256 = "38bbe77d3167b5cd554e03b1021324926f09f3825202b065951dd7638e9c37e5" }, { identifier = "cp314-android_arm64_v8a", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-aarch64-linux-android.tar.gz", sha256 = "f008321abf837fcaec569df143283ece0e764b18d8c75763200160553f906af1" },
{ identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.6/python-3.14.6-x86_64-linux-android.tar.gz", sha256 = "e04eb26607627e68d148f89de793372f54a345c91b13628567f24abcdd3bfa3e" }, { identifier = "cp314-android_x86_64", version = "3.14", url = "https://www.python.org/ftp/python/3.14.5/python-3.14.5-x86_64-linux-android.tar.gz", sha256 = "36184e31464b2b959d92c81ded8d025834342cc080623bced282a2a9a57bd47c" },
{ identifier = "cp315-android_arm64_v8a", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-aarch64-linux-android.tar.gz", sha256 = "de5e36ffc3c33b63a1ed53fe83db4dee16b003a3180ac35e5c4c203d3750e076" }, { identifier = "cp315-android_arm64_v8a", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-aarch64-linux-android.tar.gz", sha256 = "de5e36ffc3c33b63a1ed53fe83db4dee16b003a3180ac35e5c4c203d3750e076" },
{ identifier = "cp315-android_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-x86_64-linux-android.tar.gz", sha256 = "e05ef9c142ea83b41b194b16014ffe2249d27783313c3b00b97f6c93d9a56b92" }, { identifier = "cp315-android_x86_64", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-x86_64-linux-android.tar.gz", sha256 = "e05ef9c142ea83b41b194b16014ffe2249d27783313c3b00b97f6c93d9a56b92" },
] ]
[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-b14/Python-3.13-iOS-support.b14.tar.gz", sha256 = "8b5cb76ef8d8a2946052479358eeec9d54b4496cb60920e175ec1489b5cf7963" }, { 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", sha256 = "d1f95f95137a4b91dc0cbe9b99ddfc0a78918dde883c7fbe7147074a5e715274" },
{ identifier = "cp313-ios_x86_64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b14/Python-3.13-iOS-support.b14.tar.gz", sha256 = "8b5cb76ef8d8a2946052479358eeec9d54b4496cb60920e175ec1489b5cf7963" }, { 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", sha256 = "d1f95f95137a4b91dc0cbe9b99ddfc0a78918dde883c7fbe7147074a5e715274" },
{ identifier = "cp313-ios_arm64_iphonesimulator", version = "3.13", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.13-b14/Python-3.13-iOS-support.b14.tar.gz", sha256 = "8b5cb76ef8d8a2946052479358eeec9d54b4496cb60920e175ec1489b5cf7963" }, { 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", sha256 = "d1f95f95137a4b91dc0cbe9b99ddfc0a78918dde883c7fbe7147074a5e715274" },
{ identifier = "cp314-ios_arm64_iphoneos", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b10/Python-3.14-iOS-support.b10.tar.gz", sha256 = "200ef60eb67be0483ceb638daa9048f84f41a9a952707a5ad4c3198037c7b583" }, { 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", sha256 = "8e4123b543bf17fdae2e2c6c033434487752438431014eb12e6d833aa35927a8" },
{ identifier = "cp314-ios_x86_64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b10/Python-3.14-iOS-support.b10.tar.gz", sha256 = "200ef60eb67be0483ceb638daa9048f84f41a9a952707a5ad4c3198037c7b583" }, { 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", sha256 = "8e4123b543bf17fdae2e2c6c033434487752438431014eb12e6d833aa35927a8" },
{ identifier = "cp314-ios_arm64_iphonesimulator", version = "3.14", url = "https://github.com/beeware/Python-Apple-support/releases/download/3.14-b10/Python-3.14-iOS-support.b10.tar.gz", sha256 = "200ef60eb67be0483ceb638daa9048f84f41a9a952707a5ad4c3198037c7b583" }, { 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", sha256 = "8e4123b543bf17fdae2e2c6c033434487752438431014eb12e6d833aa35927a8" },
{ identifier = "cp315-ios_arm64_iphoneos", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-iOS-XCframework.tar.gz", sha256 = "dbf1095502e0b4a0dc2a4d96ae1b1d92ee8c0b7bea773862f7124ede0017e3dc" }, { identifier = "cp315-ios_arm64_iphoneos", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-iOS-XCframework.tar.gz", sha256 = "fd6b6fb8f82cf44622d28ea53b8197c89fb06505557d29d4d7a47f9386c1c896" },
{ identifier = "cp315-ios_x86_64_iphonesimulator", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-iOS-XCframework.tar.gz", sha256 = "dbf1095502e0b4a0dc2a4d96ae1b1d92ee8c0b7bea773862f7124ede0017e3dc" }, { identifier = "cp315-ios_x86_64_iphonesimulator", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-iOS-XCframework.tar.gz", sha256 = "fd6b6fb8f82cf44622d28ea53b8197c89fb06505557d29d4d7a47f9386c1c896" },
{ identifier = "cp315-ios_arm64_iphonesimulator", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b4-iOS-XCframework.tar.gz", sha256 = "dbf1095502e0b4a0dc2a4d96ae1b1d92ee8c0b7bea773862f7124ede0017e3dc" }, { identifier = "cp315-ios_arm64_iphonesimulator", version = "3.15", url = "https://www.python.org/ftp/python/3.15.0/python-3.15.0b2-iOS-XCframework.tar.gz", sha256 = "fd6b6fb8f82cf44622d28ea53b8197c89fb06505557d29d4d7a47f9386c1c896" },
] ]
+81 -92
View File
@@ -26,6 +26,67 @@
"description": "cibuildwheel's settings.", "description": "cibuildwheel's settings.",
"type": "object", "type": "object",
"properties": { "properties": {
"inherit": {
"type": "object",
"additionalProperties": false,
"properties": {
"audit-command": {
"$ref": "#/$defs/inherit"
},
"audit-requires": {
"$ref": "#/$defs/inherit"
},
"before-all": {
"$ref": "#/$defs/inherit"
},
"before-build": {
"$ref": "#/$defs/inherit"
},
"xbuild-tools": {
"$ref": "#/$defs/inherit"
},
"xbuild-files": {
"$ref": "#/$defs/inherit"
},
"before-test": {
"$ref": "#/$defs/inherit"
},
"config-settings": {
"$ref": "#/$defs/inherit"
},
"container-engine": {
"$ref": "#/$defs/inherit"
},
"environment": {
"$ref": "#/$defs/inherit"
},
"environment-pass": {
"$ref": "#/$defs/inherit"
},
"repair-wheel-command": {
"$ref": "#/$defs/inherit"
},
"test-command": {
"$ref": "#/$defs/inherit"
},
"test-extras": {
"$ref": "#/$defs/inherit"
},
"test-sources": {
"$ref": "#/$defs/inherit"
},
"test-requires": {
"$ref": "#/$defs/inherit"
},
"test-environment": {
"$ref": "#/$defs/inherit"
},
"test-runtime": {
"$ref": "#/$defs/inherit"
}
},
"title": "CIBW_INHERIT"
},
"audit-command": { "audit-command": {
"description": "Execute a shell command to audit each wheel after it is repaired. Use {wheel} for each wheel path, or {abi3_wheel} to only audit abi3 wheels.", "description": "Execute a shell command to audit each wheel after it is repaired. Use {wheel} for each wheel path, or {abi3_wheel} to only audit abi3 wheels.",
"oneOf": [ "oneOf": [
@@ -689,64 +750,7 @@
] ]
}, },
"inherit": { "inherit": {
"type": "object", "$ref": "#/properties/inherit"
"additionalProperties": false,
"properties": {
"audit-command": {
"$ref": "#/$defs/inherit"
},
"audit-requires": {
"$ref": "#/$defs/inherit"
},
"before-all": {
"$ref": "#/$defs/inherit"
},
"before-build": {
"$ref": "#/$defs/inherit"
},
"xbuild-tools": {
"$ref": "#/$defs/inherit"
},
"xbuild-files": {
"$ref": "#/$defs/inherit"
},
"before-test": {
"$ref": "#/$defs/inherit"
},
"config-settings": {
"$ref": "#/$defs/inherit"
},
"container-engine": {
"$ref": "#/$defs/inherit"
},
"environment": {
"$ref": "#/$defs/inherit"
},
"environment-pass": {
"$ref": "#/$defs/inherit"
},
"repair-wheel-command": {
"$ref": "#/$defs/inherit"
},
"test-command": {
"$ref": "#/$defs/inherit"
},
"test-extras": {
"$ref": "#/$defs/inherit"
},
"test-sources": {
"$ref": "#/$defs/inherit"
},
"test-requires": {
"$ref": "#/$defs/inherit"
},
"test-environment": {
"$ref": "#/$defs/inherit"
},
"test-runtime": {
"$ref": "#/$defs/inherit"
}
}
}, },
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
@@ -875,6 +879,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -1014,6 +1021,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -1099,6 +1109,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -1184,6 +1197,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -1203,40 +1219,7 @@
"$ref": "#/properties/before-test" "$ref": "#/properties/before-test"
}, },
"build-frontend": { "build-frontend": {
"default": "pyodide-build", "$ref": "#/properties/build-frontend"
"description": "On the pyodide platform, the build frontend must be \"pyodide-build\"",
"oneOf": [
{
"enum": [
"pyodide-build"
]
},
{
"type": "string",
"pattern": "^pyodide-build; ?args:"
},
{
"type": "object",
"additionalProperties": false,
"required": [
"name"
],
"properties": {
"name": {
"enum": [
"pyodide-build"
]
},
"args": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
],
"title": "CIBW_BUILD_FRONTEND"
}, },
"build-verbosity": { "build-verbosity": {
"$ref": "#/properties/build-verbosity" "$ref": "#/properties/build-verbosity"
@@ -1289,6 +1272,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -1374,6 +1360,9 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"inherit": {
"$ref": "#/properties/inherit"
},
"audit-command": { "audit-command": {
"$ref": "#/properties/audit-command" "$ref": "#/properties/audit-command"
}, },
@@ -8,18 +8,18 @@ build==1.5.0
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# 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
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -39,7 +39,7 @@ packaging==26.2
# wheel # wheel
pip==26.1.2 pip==26.1.2
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# pyodide-build # pyodide-build
# python-discovery # python-discovery
@@ -52,7 +52,7 @@ pydantic-core==2.46.4
# via pydantic # via pydantic
pygments==2.20.0 pygments==2.20.0
# via rich # via rich
pyodide-build==0.36.0 pyodide-build==0.35.0
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.5.0 pyodide-cli==0.5.0
# via # via
@@ -62,7 +62,7 @@ pyodide-lock==0.1.3
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via pyodide-build # via pyodide-build
@@ -72,7 +72,7 @@ rich==15.0.0
# pyodide-cli # pyodide-cli
ruamel-yaml==0.19.1 ruamel-yaml==0.19.1
# via pyodide-build # via pyodide-build
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# pydantic # pydantic
# pydantic-core # pydantic-core
@@ -81,7 +81,7 @@ typing-inspection==0.4.2
# via pydantic # via pydantic
urllib3==2.7.0 urllib3==2.7.0
# via requests # via requests
virtualenv==21.6.1 virtualenv==21.4.2
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -8,18 +8,18 @@ build==1.5.0
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# 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
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -39,7 +39,7 @@ packaging==26.2
# wheel # wheel
pip==26.1.2 pip==26.1.2
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# pyodide-build # pyodide-build
# python-discovery # python-discovery
@@ -52,7 +52,7 @@ pydantic-core==2.46.4
# via pydantic # via pydantic
pygments==2.20.0 pygments==2.20.0
# via rich # via rich
pyodide-build==0.36.0 pyodide-build==0.35.0
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.5.0 pyodide-cli==0.5.0
# via # via
@@ -62,7 +62,7 @@ pyodide-lock==0.1.3
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via pyodide-build # via pyodide-build
@@ -72,7 +72,7 @@ rich==15.0.0
# pyodide-cli # pyodide-cli
ruamel-yaml==0.19.1 ruamel-yaml==0.19.1
# via pyodide-build # via pyodide-build
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# pydantic # pydantic
# pydantic-core # pydantic-core
@@ -81,7 +81,7 @@ typing-inspection==0.4.2
# via pydantic # via pydantic
urllib3==2.7.0 urllib3==2.7.0
# via requests # via requests
virtualenv==21.6.1 virtualenv==21.4.2
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -8,18 +8,18 @@ build==1.5.0
# via # via
# -r .nox/update_constraints/tmp/constraints-pyodide.in # -r .nox/update_constraints/tmp/constraints-pyodide.in
# pyodide-build # pyodide-build
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# 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
# pyodide-build # pyodide-build
# pyodide-cli # pyodide-cli
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -39,7 +39,7 @@ packaging==26.2
# wheel # wheel
pip==26.1.2 pip==26.1.2
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# pyodide-build # pyodide-build
# python-discovery # python-discovery
@@ -52,7 +52,7 @@ pydantic-core==2.46.4
# via pydantic # via pydantic
pygments==2.20.0 pygments==2.20.0
# via rich # via rich
pyodide-build==0.36.0 pyodide-build==0.35.0
# via -r .nox/update_constraints/tmp/constraints-pyodide.in # via -r .nox/update_constraints/tmp/constraints-pyodide.in
pyodide-cli==0.5.0 pyodide-cli==0.5.0
# via # via
@@ -62,7 +62,7 @@ pyodide-lock==0.1.3
# via pyodide-build # via pyodide-build
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via pyodide-build # via pyodide-build
@@ -72,7 +72,7 @@ rich==15.0.0
# pyodide-cli # pyodide-cli
ruamel-yaml==0.19.1 ruamel-yaml==0.19.1
# via pyodide-build # via pyodide-build
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# pydantic # pydantic
# pydantic-core # pydantic-core
@@ -81,7 +81,7 @@ typing-inspection==0.4.2
# via pydantic # via pydantic
urllib3==2.7.0 urllib3==2.7.0
# via requests # via requests
virtualenv==21.6.1 virtualenv==21.4.2
# via # via
# build # build
# pyodide-build # pyodide-build
@@ -16,19 +16,19 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
exceptiongroup==1.3.1 exceptiongroup==1.3.1
# via cattrs # via cattrs
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -60,9 +60,9 @@ pefile==2024.8.26
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -75,19 +75,19 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
tomli==2.4.1 tomli==2.4.1
# via build # via build
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -99,7 +99,7 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==4.1.0 zipp==4.1.0
# via importlib-metadata # via importlib-metadata
@@ -16,17 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -54,11 +54,12 @@ pefile==2024.8.26
# via # via
# abi3audit # abi3audit
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2; implementation_name != "graalpy" or platform_system != "Windows"
pip==26.0.1; implementation_name == "graalpy" and platform_system == "Windows"
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -71,17 +72,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -91,5 +92,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -16,18 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1; implementation_name != "graalpy" filelock==3.29.1
filelock==3.29.7; implementation_name == "graalpy"
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -58,9 +57,9 @@ pefile==2024.8.26
pip==26.1.2; implementation_name != "graalpy" or platform_system != "Windows" pip==26.1.2; implementation_name != "graalpy" or platform_system != "Windows"
pip==26.0.1; implementation_name == "graalpy" and platform_system == "Windows" pip==26.0.1; implementation_name == "graalpy" and platform_system == "Windows"
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -73,17 +72,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -93,5 +92,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -16,17 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -56,9 +56,9 @@ pefile==2024.8.26
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -71,17 +71,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -91,5 +91,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -16,17 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -56,9 +56,9 @@ pefile==2024.8.26
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -71,17 +71,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -91,5 +91,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -16,17 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -56,9 +56,9 @@ pefile==2024.8.26
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -71,17 +71,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -91,5 +91,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
@@ -16,15 +16,15 @@ build==1.4.4
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==25.3.0 cattrs==25.3.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
exceptiongroup==1.3.1 exceptiongroup==1.3.1
# via cattrs # via cattrs
@@ -77,7 +77,7 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.32.5 requests==2.32.5
# via # via
@@ -89,7 +89,7 @@ rich==14.2.0
# via abi3audit # via abi3audit
tomli==2.4.1 tomli==2.4.1
# via build # via build
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -101,7 +101,7 @@ urllib3==2.6.3
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
zipp==3.23.1 zipp==3.23.1
# via importlib-metadata # via importlib-metadata
+10 -10
View File
@@ -16,17 +16,17 @@ build==1.5.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
cattrs==26.1.0 cattrs==26.1.0
# via requests-cache # via requests-cache
certifi==2026.6.17 certifi==2026.5.20
# via requests # via requests
charset-normalizer==3.4.9 charset-normalizer==3.4.7
# via requests # via requests
delocate==0.13.0 delocate==0.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
delvewheel==1.13.0 delvewheel==1.13.0
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
distlib==0.4.3 distlib==0.4.1
# via virtualenv # via virtualenv
filelock==3.31.1 filelock==3.29.1
# via # via
# python-discovery # python-discovery
# virtualenv # virtualenv
@@ -56,9 +56,9 @@ pefile==2024.8.26
# delvewheel # delvewheel
pip==26.1.2 pip==26.1.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
pkgconf==3.0.1.post0 pkgconf==2.5.1.post2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
platformdirs==4.10.1 platformdirs==4.10.0
# via # via
# python-discovery # python-discovery
# requests-cache # requests-cache
@@ -71,17 +71,17 @@ pygments==2.20.0
# via rich # via rich
pyproject-hooks==1.2.0 pyproject-hooks==1.2.0
# via build # via build
python-discovery==1.4.4 python-discovery==1.4.0
# via virtualenv # via virtualenv
requests==2.34.2 requests==2.34.2
# via # via
# abi3audit # abi3audit
# requests-cache # requests-cache
requests-cache==1.3.3 requests-cache==1.3.2
# via abi3audit # via abi3audit
rich==15.0.0 rich==15.0.0
# via abi3audit # via abi3audit
typing-extensions==4.16.0 typing-extensions==4.15.0
# via # via
# cattrs # cattrs
# delocate # delocate
@@ -91,5 +91,5 @@ urllib3==2.7.0
# via # via
# requests # requests
# requests-cache # requests-cache
virtualenv==21.6.1 virtualenv==21.4.2
# via -r cibuildwheel/resources/constraints.in # via -r cibuildwheel/resources/constraints.in
-1
View File
@@ -79,4 +79,3 @@ repair-wheel-command = "auditwheel repair --ldpaths {ldpaths} -w {dest_dir} {whe
[tool.cibuildwheel.pyodide] [tool.cibuildwheel.pyodide]
audit-command = "" audit-command = ""
build-frontend = "pyodide-build"
+2 -2
View File
@@ -1,4 +1,4 @@
url = "https://nodejs.org/dist/" url = "https://nodejs.org/dist/"
v24 = "v24.18.0" v24 = "v24.16.0"
v22 = "v22.23.1" v22 = "v22.22.3"
v20 = "v20.20.2" v20 = "v20.20.2"
+34 -34
View File
@@ -1,54 +1,54 @@
[x86_64] [x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64@sha256:0d25b049964b2549b83384036abdff06789a8c0b1e9ff003ec80f0d531f79e50 # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64@sha256:a61875a2f84cab7df8de222ff12cabc08ff86eb4ad402ac90ba7bdaed9600cca # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64@sha256:b6e1f264da7bf4e8db3e6a625ea1ecaf1e52290253df8588f71e4a9e50a85a17 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64@sha256:fd0694e23637ae8d13433c58f647aba1aae5de4fd50350201307be453a8b2ff4 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2026.06.04-1
[i686] [i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686@sha256:9833ed0665e4bd2aceeda6f7ea81b69c75a941464b659edf62c98aa63526d1ba # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686@sha256:3a4de216ae551c1cbb8f93d4bbf9faebe7fb16a67afa3380b9a3ed2cc7b80fcf # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686@sha256:1fc55618156152a6570991a6ee81038fd507b48c41cbdede495931146b074869 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686@sha256:a85be8fc5aa7fa291b8bee5647469d3d48dd26600cc7295553ff47ca60906ff2 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2026.06.04-1
[aarch64] [aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64@sha256:ae34a6ceeefe0b535c525b2e96f297311c8f1e01cfd8b9be5f647eece5b5c60b # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64@sha256:162c81dfd3efc710732a571717d3c916a6945ebf279e879ddee3243af96fe46f # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64@sha256:ae032906c631ad572a91bcc9545023d327822912957ae85a57c85181836662b6 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64@sha256:e6ac3eca5f7d2cd5b8267b94b65d9a693e7ba06f5ba4c6643b1b0e6f9ae2cde3 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2026.06.04-1
[ppc64le] [ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le@sha256:7e311ceece0fd3faa54a8539fb0b7906ee2ac068ecc39095e48ed1097312eaa0 # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le@sha256:32ec597dd87e27980750115a6c020cae54fd17386e18d86d695e35e6b3a3e0da # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le@sha256:7f649dea6f31fbc4ca6d665e78e87a192b55e739c44ed9965129956be77c4e3d # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_ppc64le:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le@sha256:d59ad21615cf5b83cc9046cf7c44d07e8ef1247333e8a72147d7c781008605c1 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2026.06.04-1
[s390x] [s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x@sha256:e392818123219665c259c9a5e389cecd978918dc279fe8e3542864f1067b9cdb # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_s390x:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x@sha256:9c4f347bc43b1b799a296f6801a8845af132fa6f919cc6237b889c8d2e16ae01 # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x@sha256:37fe79ec71fed0eaa4d6edfb22244699877e3cd92a2ca4679bf9e4fd5f45c61d # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_s390x:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x@sha256:e29d28c68a0bd4594fd41cb2435ca64388038b05c24e77b34f186ff90a2968c4 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2026.06.04-1
[pypy_x86_64] [pypy_x86_64]
manylinux2014 = quay.io/pypa/manylinux2014_x86_64@sha256:0d25b049964b2549b83384036abdff06789a8c0b1e9ff003ec80f0d531f79e50 # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64@sha256:a61875a2f84cab7df8de222ff12cabc08ff86eb4ad402ac90ba7bdaed9600cca # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64@sha256:b6e1f264da7bf4e8db3e6a625ea1ecaf1e52290253df8588f71e4a9e50a85a17 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_x86_64:2026.06.04-1
[pypy_i686] [pypy_i686]
manylinux2014 = quay.io/pypa/manylinux2014_i686@sha256:9833ed0665e4bd2aceeda6f7ea81b69c75a941464b659edf62c98aa63526d1ba # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_i686:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686@sha256:3a4de216ae551c1cbb8f93d4bbf9faebe7fb16a67afa3380b9a3ed2cc7b80fcf # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_i686:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686@sha256:1fc55618156152a6570991a6ee81038fd507b48c41cbdede495931146b074869 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_i686:2026.06.04-1
[pypy_aarch64] [pypy_aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64@sha256:ae34a6ceeefe0b535c525b2e96f297311c8f1e01cfd8b9be5f647eece5b5c60b # 2026.07.19-1 manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2026.06.04-1
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64@sha256:162c81dfd3efc710732a571717d3c916a6945ebf279e879ddee3243af96fe46f # 2026.07.19-1 manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2026.06.04-1
manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64@sha256:ae032906c631ad572a91bcc9545023d327822912957ae85a57c85181836662b6 # 2026.07.19-1 manylinux_2_34 = quay.io/pypa/manylinux_2_34_aarch64:2026.06.04-1
[armv7l] [armv7l]
manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l@sha256:a58ece566251a37b3b4cd17d7ef85d88df05f80670c7dfe80c1b1ffe4cd00bf8 # 2026.07.19-1 manylinux_2_31 = quay.io/pypa/manylinux_2_31_armv7l:2026.06.04-1
manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l@sha256:c8dba9616907a810e2668afb88153bf47a84422933733dbf4ea7b561af5e8d1e # 2026.07.19-1 manylinux_2_35 = quay.io/pypa/manylinux_2_35_armv7l:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l@sha256:d87cbc211df71486a6a90fb2bece474166f3e2dcf81bbfc4be07607fd64185b0 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_armv7l:2026.06.04-1
[riscv64] [riscv64]
manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64@sha256:04b3acc69a6cebb10ac1252587d202acce6445d91c783d3f92229bb2b2483069 # 2026.07.19-1 manylinux_2_39 = quay.io/pypa/manylinux_2_39_riscv64:2026.06.04-1
musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64@sha256:2d36623ffc59785e124ecf2992456847baaf2f2e0a87e64d23f2f6a69e5a0357 # 2026.07.19-1 musllinux_1_2 = quay.io/pypa/musllinux_1_2_riscv64:2026.06.04-1
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
default = { version = "21.6.1", url = "https://github.com/pypa/get-virtualenv/releases/download/21.6.1/virtualenv.pyz", sha256 = "32490c6eea415c3a8f44ee112bbef07bc7b70a0aba706672240c6c66d4f7d9cc" } default = { version = "21.4.2", url = "https://github.com/pypa/get-virtualenv/releases/download/21.4.2/virtualenv.pyz", sha256 = "b54c48b9c81468403626762747c5ee5939616f18f46c3c4bbebdbe0aa3a8ba1d" }
+47 -2
View File
@@ -111,7 +111,7 @@ def parse_key_value_string(
if kw_arg_names is None: if kw_arg_names is None:
kw_arg_names = [] kw_arg_names = []
all_field_names = None if ("*" in kw_arg_names) else [*positional_arg_names, *kw_arg_names] all_field_names = [*positional_arg_names, *kw_arg_names]
shlexer = shlex.shlex(key_value_string, posix=True, punctuation_chars=";") shlexer = shlex.shlex(key_value_string, posix=True, punctuation_chars=";")
shlexer.commenters = "" shlexer.commenters = ""
@@ -128,7 +128,7 @@ def parse_key_value_string(
# check to see if the option name is specified # check to see if the option name is specified
field_name, sep, first_value = field[0].partition(":") field_name, sep, first_value = field[0].partition(":")
if sep: if sep:
if (all_field_names is not None) and (field_name not in all_field_names): if field_name not in all_field_names:
msg = f"Failed to parse {key_value_string!r}. Unknown field name {field_name!r}" msg = f"Failed to parse {key_value_string!r}. Unknown field name {field_name!r}"
raise ValueError(msg) raise ValueError(msg)
@@ -147,6 +147,51 @@ def parse_key_value_string(
return dict(result) return dict(result)
def parse_arbitrary_key_value_string(
key_value_string: str, default_value: str | None = None
) -> dict[str, list[str]]:
"""
Parses a string like
"before-build; before-test: append; after-test: prepend"
or
"package1: some/header.h some/library.a; package2: other/header.h"
There are no restrictions on the keys than can be set.
No positional arguments are allowed. Words without a colon attached are
interpreted as keys. Keys without a value will be assigned the
default_value if provided, otherwise throw an error.
"""
shlexer = shlex.shlex(key_value_string, posix=True, punctuation_chars=";")
shlexer.commenters = ""
shlexer.whitespace_split = True
parts = list(shlexer)
# parts now looks like
# ['before-build', ';', 'before-test:', 'append', ';', 'after-test:', 'prepend']
# split by semicolon
result: defaultdict[str, list[str]] = defaultdict(list)
fields = [list(group) for k, group in itertools.groupby(parts, lambda x: x == ";") if not k]
for field in fields:
# check to see if the option name is specified
field_name, sep, first_value = field[0].partition(":")
if sep:
# the colon was present, so the first value is the value after the colon
values = ([first_value] if first_value else []) + field[1:]
result[field_name] += values
else:
# no colon, so it's a key (or set of keys) without values
if default_value is None:
msg = f"Failed to parse {key_value_string!r}. No value specified for {field_name!r}. Expected ':' followed by a value."
raise ValueError(msg)
for key in field:
result[key].append(default_value)
return dict(result)
@dataclasses.dataclass(order=True) @dataclasses.dataclass(order=True)
class FlexibleVersion: class FlexibleVersion:
version_parts: tuple[int, ...] = dataclasses.field(init=False, repr=False) version_parts: tuple[int, ...] = dataclasses.field(init=False, repr=False)
+1 -4
View File
@@ -3,7 +3,6 @@ from __future__ import annotations
__lazy_modules__ = {"tomllib"} __lazy_modules__ = {"tomllib"}
import functools import functools
import os
import tomllib import tomllib
from pathlib import Path from pathlib import Path
@@ -19,9 +18,7 @@ FREE_THREAD_ENABLE_314: Final[Path] = PATH / "free-threaded-enable-314.xml"
FREE_THREAD_ENABLE_315: Final[Path] = PATH / "free-threaded-enable-315.xml" FREE_THREAD_ENABLE_315: Final[Path] = PATH / "free-threaded-enable-315.xml"
NODEJS: Final[Path] = PATH / "nodejs.toml" NODEJS: Final[Path] = PATH / "nodejs.toml"
DEFAULTS: Final[Path] = PATH / "defaults.toml" DEFAULTS: Final[Path] = PATH / "defaults.toml"
PINNED_DOCKER_IMAGES: Final[Path] = Path( PINNED_DOCKER_IMAGES: Final[Path] = PATH / "pinned_docker_images.cfg"
os.environ.get("CIBW_INTERNAL_PINNED_DOCKER_IMAGES", str(PATH / "pinned_docker_images.cfg"))
)
BUILD_PLATFORMS: Final[Path] = PATH / "build-platforms.toml" BUILD_PLATFORMS: Final[Path] = PATH / "build-platforms.toml"
CONSTRAINTS: Final[Path] = PATH / "constraints.txt" CONSTRAINTS: Final[Path] = PATH / "constraints.txt"
VIRTUALENV: Final[Path] = PATH / "virtualenv.toml" VIRTUALENV: Final[Path] = PATH / "virtualenv.toml"
+1 -13
View File
@@ -152,10 +152,6 @@ def virtualenv(
venv. Otherwise, pip is installed. venv. Otherwise, pip is installed.
""" """
# the unresolved path, so e.g. the python.org framework bin directory is
# used rather than the internal location of the real binary
base_python_bin_dir = None if _IS_WIN else python.parent
# virtualenv may fail if this is a symlink. # virtualenv may fail if this is a symlink.
python = python.resolve() python = python.resolve()
@@ -193,7 +189,7 @@ def virtualenv(
python, python,
venv_path, venv_path,
) )
venv_env = activate_virtualenv(venv_path, env=env, base_python_bin_dir=base_python_bin_dir) venv_env = activate_virtualenv(venv_path, env=env)
if not use_uv and pip_version == "embed": if not use_uv and pip_version == "embed":
call( call(
"python", "python",
@@ -212,19 +208,11 @@ def virtualenv(
def activate_virtualenv( def activate_virtualenv(
venv_path: Path, venv_path: Path,
env: dict[str, str] | None = None, env: dict[str, str] | None = None,
base_python_bin_dir: Path | None = None,
) -> dict[str, str]: ) -> dict[str, str]:
""" """
Return a copy of the environment with the virtualenv at `venv_path` activated. Return a copy of the environment with the virtualenv at `venv_path` activated.
If given, `base_python_bin_dir` is placed on PATH right after the venv, so
that scripts installed alongside the base interpreter that aren't copied
into the venv (such as python3-config, see #2021) resolve to the matching
interpreter.
""" """
paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")] paths = [str(venv_path), str(venv_path / "Scripts")] if _IS_WIN else [str(venv_path / "bin")]
if base_python_bin_dir is not None:
paths.append(str(base_python_bin_dir))
venv_env = os.environ.copy() if env is None else env.copy() venv_env = os.environ.copy() if env is None else env.copy()
venv_env["PATH"] = os.pathsep.join([*paths, venv_env["PATH"]]) venv_env["PATH"] = os.pathsep.join([*paths, venv_env["PATH"]])
venv_env["VIRTUAL_ENV"] = str(venv_path) venv_env["VIRTUAL_ENV"] = str(venv_path)
-22
View File
@@ -5,28 +5,6 @@ ref: changelog
# Changelog # Changelog
### v4.1.1
_24 July 2026_
- ✨ Adds `pyodide-build` as a separate [`build-frontend`](https://cibuildwheel.pypa.io/en/stable/options/#build-frontend), now the default frontend for Pyodide, with verbosity flags handling. Any other frontend is ignored with a warning on Pyodide. (#2609, #2945)
- 🔐 Uses digests instead of tags for pinned container images, strengthening supply-chain security. The human-readable tags remain as comments in `pinned_docker_images.cfg`. (#2915)
- 🐛 Fixes platform-specific [`test-runtime`](https://cibuildwheel.pypa.io/en/stable/options/#test-runtime) environment variables (e.g. `CIBW_TEST_RUNTIME_ANDROID`) not being honored (#2941)
- 🐛 Fixes quoting of [`test-requires`](https://cibuildwheel.pypa.io/en/stable/options/#test-requires) and [`audit-requires`](https://cibuildwheel.pypa.io/en/stable/options/#audit-requires) so PEP 508 specifiers containing spaces work (#2913)
- 🐛 Makes [`archs`](https://cibuildwheel.pypa.io/en/stable/options/#archs) parsing case-insensitive and platform-aware, so e.g. `arm64` works on Windows (#2920)
- 🐛 Uses an absolute path for the `{project}` placeholder in [`config-settings`](https://cibuildwheel.pypa.io/en/stable/options/#config-settings) (#2934)
- 🐛 Validates the [`pyodide-version`](https://cibuildwheel.pypa.io/en/stable/options/#pyodide-version) option against the build identifier with a clear error (#2925)
- 🐛 Fixes PyPy installs on macOS after PyPy switched its downloads from `.tar.bz2` to `.tar.gz` (#2939)
- 🐛 Makes a matching `python3-config` available in the build and test venvs on macOS (#2922)
- 🛠 Updates dependencies and container pins (#2917, #2935, #2939)
- 🛠 Updates Android tests to current Python versions and the new test repository URL (#2933)
- 🛠 Drops the `orjson` dependency, no longer used by mypy 2+ (#2923)
- 📚 Builds the docs with properdocs, a MkDocs fork (#2946)
- 📚 Adds the missing `cp314-pyodide_wasm32` entry to the build identifier table (#2947)
- 📚 Removes outdated notes about the `pip wheel` build frontend and ClearLinux (#2926)
- 💼 Adds a "CI: PyPy EoL" PR label to run PyPy EoL tests on PRs (#2930)
- 💼 Updates CI action pins and pre-commit hooks (#2914, #2932, #2938, #2940, #2942, #2943)
### v4.1.0 ### v4.1.0
_12 June 2026_ _12 June 2026_
+71 -18
View File
@@ -66,10 +66,11 @@ placed in `[tool.cibuildwheel]` and are lower case, with dashes, following
common [TOML](https://toml.io) practice. Anything placed in subsections common [TOML](https://toml.io) practice. Anything placed in subsections
named after a platform will only affect those platforms. Platform-specific named after a platform will only affect those platforms. Platform-specific
values replace the corresponding global value for that platform; table options values replace the corresponding global value for that platform; table options
are not merged key by key. Lists can be used instead of strings for items that are not merged key by key unless you configure [inheritance](#inherit). Lists can
are naturally a list. Multiline strings also work just like in the environment be used instead of strings for items that are naturally a list. Multiline strings
variables. Environment variable overrides, such as `CIBW_TEST_COMMAND` and also work just like in the environment variables. Environment variable overrides,
`CIBW_TEST_COMMAND_LINUX`, will take precedence if defined. such as `CIBW_TEST_COMMAND` and `CIBW_TEST_COMMAND_LINUX`, take precedence if
defined.
The example above using environment variables could have been written like this: The example above using environment variables could have been written like this:
@@ -113,9 +114,9 @@ trigger new containers, one per image.
The ``output-dir``, ``build``, ``skip``, ``test_skip`` selectors, and architectures cannot be overridden. The ``output-dir``, ``build``, ``skip``, ``test_skip`` selectors, and architectures cannot be overridden.
You can specify a table of overrides in `inherit={}`, any list or table in this By default, values in an override replace values from the main configuration or
list will inherit from previous overrides or the main configuration. The valid earlier overrides. You can instead [extend a list or table option](#inherit) by
options are `"none"` (the default), `"append"`, and `"prepend"`. setting an `inherit` rule for it.
#### Examples: #### Examples:
@@ -175,14 +176,50 @@ This example will provide the command `"pyproject-before && pyproject && pyproje
on Python 3.11, and will have `environment = {FOO="BAZ", "PYTHON"="MONTY", "HAM"="EGGS"}`. on Python 3.11, and will have `environment = {FOO="BAZ", "PYTHON"="MONTY", "HAM"="EGGS"}`.
## Extending existing options {: #inherit } ## Option inheritance {: #inherit }
In the TOML configuration, you can choose how tables and lists are inherited. As cibuildwheel reads its configuration, each layer normally replaces the value
By default, all values are overridden completely (`"none"`) but sometimes you'd from the previous layer. The layers, from lowest to highest precedence, are:
rather `"append"` or `"prepend"` to an existing list or table. You can do this
with the `inherit` table in overrides. For example, if you want to add an environment 1. cibuildwheel's defaults
variable for CPython 3.11, without `inherit` you'd have to repeat all the 2. `[tool.cibuildwheel]`
original environment variables in the override. With `inherit`, it's just: 3. `[tool.cibuildwheel.<platform>]`
4. matching `[[tool.cibuildwheel.overrides]]` entries, in order
5. `CIBW_<OPTION>`
6. `CIBW_<OPTION>_<PLATFORM>`
For list and table options, you can use an `inherit` rule to merge a value with
the value accumulated from the preceding layers instead. The available rules
are `"none"` (replace the previous value, the default), `"append"`, and
`"prepend"`.
In `pyproject.toml`, set the rule in the same table as the value it applies to.
For example, this adds Twine checks to the default audit configuration:
```toml
[tool.cibuildwheel]
inherit.audit-requires = "append"
inherit.audit-command = "append"
audit-requires = ["twine"]
audit-command = "twine check {wheel}"
```
Inheritance can also combine global and platform-specific configuration. This
example runs a Linux-specific setup command before the global command:
```toml
[tool.cibuildwheel]
before-all = "make -C third_party_lib"
[tool.cibuildwheel.linux]
inherit.before-all = "prepend"
before-all = "yum install -y libffi-devel"
```
The same mechanism remains available in overrides. For example, if you want to
add an environment variable for CPython 3.11, without `inherit` you'd have to
repeat all the original environment variables in the override. With `inherit`,
it's just:
```toml ```toml
[[tool.cibuildwheel.overrides]] [[tool.cibuildwheel.overrides]]
@@ -210,7 +247,23 @@ repair-wheel-command = "echo 'After repair'"
``` ```
As seen in this example, you can have multiple overrides match - they match top As seen in this example, you can have multiple overrides match - they match top
to bottom, with the config being accumulated. If you need platform-specific to bottom, with the config being accumulated.
inheritance, you can use `select = "*-????linux_*"` for Linux, `select =
"*-win_*"` for Windows, and `select = "*-macosx_*"` for macOS. As always, For environment variables, specify the rules in `CIBW_INHERIT`. Rules are
environment variables will completely override any TOML configuration. separated by semicolons and use lowercase option names. A rule without an
explicit value defaults to `append`:
```yaml
CIBW_AUDIT_REQUIRES: twine
CIBW_AUDIT_COMMAND: "twine check {wheel}"
CIBW_INHERIT: "audit-requires; audit-command"
```
To control a platform-specific environment variable, add the lowercase platform
suffix to the option name. For example, this prepends `CIBW_BEFORE_ALL_LINUX` to
the value accumulated from the lower-precedence layers:
```yaml
CIBW_BEFORE_ALL_LINUX: yum install -y libffi-devel
CIBW_INHERIT: "before-all-linux: prepend"
```
+3 -3
View File
@@ -158,7 +158,7 @@ There are two suggested methods for keeping cibuildwheel up to date that instead
If you use GitHub Actions for builds, you can use cibuildwheel as an action: If you use GitHub Actions for builds, you can use cibuildwheel as an action:
```yaml ```yaml
uses: pypa/cibuildwheel@v4.1.1 uses: pypa/cibuildwheel@v4.1.0
``` ```
This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal. 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.
@@ -183,7 +183,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==4.1.1 cibuildwheel==4.1.0
``` ```
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this: 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:
@@ -402,7 +402,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==4.1.1 --output-dir wheelhouse pipx run cibuildwheel==4.1.0 --output-dir wheelhouse
pipx run twine upload wheelhouse/*.whl pipx run twine upload wheelhouse/*.whl
``` ```
+19 -17
View File
@@ -64,7 +64,7 @@ When setting the options, you can use shell-style globbing syntax, as per [fnmat
| Python 3.11 | cp311-macosx_x86_64<br/>cp311-macosx_universal2<br/>cp311-macosx_arm64 | cp311-win_amd64<br/>cp311-win32<br/>cp311-win_arm64 | cp311-manylinux_x86_64<br/>cp311-manylinux_i686<br/>cp311-musllinux_x86_64<br/>cp311-musllinux_i686 | cp311-manylinux_aarch64<br/>cp311-manylinux_ppc64le<br/>cp311-manylinux_s390x<br/>cp311-manylinux_armv7l<br/>cp311-manylinux_riscv64<br/>cp311-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l<br/>cp311-musllinux_riscv64 | | | | | Python 3.11 | cp311-macosx_x86_64<br/>cp311-macosx_universal2<br/>cp311-macosx_arm64 | cp311-win_amd64<br/>cp311-win32<br/>cp311-win_arm64 | cp311-manylinux_x86_64<br/>cp311-manylinux_i686<br/>cp311-musllinux_x86_64<br/>cp311-musllinux_i686 | cp311-manylinux_aarch64<br/>cp311-manylinux_ppc64le<br/>cp311-manylinux_s390x<br/>cp311-manylinux_armv7l<br/>cp311-manylinux_riscv64<br/>cp311-musllinux_aarch64<br/>cp311-musllinux_ppc64le<br/>cp311-musllinux_s390x<br/>cp311-musllinux_armv7l<br/>cp311-musllinux_riscv64 | | | |
| Python 3.12 | cp312-macosx_x86_64<br/>cp312-macosx_universal2<br/>cp312-macosx_arm64 | cp312-win_amd64<br/>cp312-win32<br/>cp312-win_arm64 | cp312-manylinux_x86_64<br/>cp312-manylinux_i686<br/>cp312-musllinux_x86_64<br/>cp312-musllinux_i686 | cp312-manylinux_aarch64<br/>cp312-manylinux_ppc64le<br/>cp312-manylinux_s390x<br/>cp312-manylinux_armv7l<br/>cp312-manylinux_riscv64<br/>cp312-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l<br/>cp312-musllinux_riscv64 | | | cp312-pyodide_wasm32 | | Python 3.12 | cp312-macosx_x86_64<br/>cp312-macosx_universal2<br/>cp312-macosx_arm64 | cp312-win_amd64<br/>cp312-win32<br/>cp312-win_arm64 | cp312-manylinux_x86_64<br/>cp312-manylinux_i686<br/>cp312-musllinux_x86_64<br/>cp312-musllinux_i686 | cp312-manylinux_aarch64<br/>cp312-manylinux_ppc64le<br/>cp312-manylinux_s390x<br/>cp312-manylinux_armv7l<br/>cp312-manylinux_riscv64<br/>cp312-musllinux_aarch64<br/>cp312-musllinux_ppc64le<br/>cp312-musllinux_s390x<br/>cp312-musllinux_armv7l<br/>cp312-musllinux_riscv64 | | | cp312-pyodide_wasm32 |
| Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64 | cp313-android_arm64_v8a<br/>cp313-android_x86_64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 | | Python 3.13 | cp313-macosx_x86_64<br/>cp313-macosx_universal2<br/>cp313-macosx_arm64 | cp313-win_amd64<br/>cp313-win32<br/>cp313-win_arm64 | cp313-manylinux_x86_64<br/>cp313-manylinux_i686<br/>cp313-musllinux_x86_64<br/>cp313-musllinux_i686 | cp313-manylinux_aarch64<br/>cp313-manylinux_ppc64le<br/>cp313-manylinux_s390x<br/>cp313-manylinux_armv7l<br/>cp313-manylinux_riscv64<br/>cp313-musllinux_aarch64<br/>cp313-musllinux_ppc64le<br/>cp313-musllinux_s390x<br/>cp313-musllinux_armv7l<br/>cp313-musllinux_riscv64 | cp313-android_arm64_v8a<br/>cp313-android_x86_64 | cp313-ios_arm64_iphoneos<br/>cp313-ios_arm64_iphonesimulator<br/>cp313-ios_x86_64_iphonesimulator | cp313-pyodide_wasm32 |
| Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64<br><br>cp314t-macosx_x86_64<br/>cp314t-macosx_universal2<br/>cp314t-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64<br><br>cp314t-win_amd64<br/>cp314t-win32<br/>cp314t-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686<br><br>cp314t-manylinux_x86_64<br/>cp314t-manylinux_i686<br/>cp314t-musllinux_x86_64<br/>cp314t-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64<br><br>cp314t-manylinux_aarch64<br/>cp314t-manylinux_ppc64le<br/>cp314t-manylinux_s390x<br/>cp314t-manylinux_armv7l<br/>cp314t-manylinux_riscv64<br/>cp314t-musllinux_aarch64<br/>cp314t-musllinux_ppc64le<br/>cp314t-musllinux_s390x<br/>cp314t-musllinux_armv7l<br/>cp314t-musllinux_riscv64 | cp314-android_arm64_v8a<br/>cp314-android_x86_64 | cp314-ios_arm64_iphoneos<br/>cp314-ios_arm64_iphonesimulator<br/>cp314-ios_x86_64_iphonesimulator | cp314-pyodide_wasm32 | | Python 3.14 | cp314-macosx_x86_64<br/>cp314-macosx_universal2<br/>cp314-macosx_arm64<br><br>cp314t-macosx_x86_64<br/>cp314t-macosx_universal2<br/>cp314t-macosx_arm64 | cp314-win_amd64<br/>cp314-win32<br/>cp314-win_arm64<br><br>cp314t-win_amd64<br/>cp314t-win32<br/>cp314t-win_arm64 | cp314-manylinux_x86_64<br/>cp314-manylinux_i686<br/>cp314-musllinux_x86_64<br/>cp314-musllinux_i686<br><br>cp314t-manylinux_x86_64<br/>cp314t-manylinux_i686<br/>cp314t-musllinux_x86_64<br/>cp314t-musllinux_i686 | cp314-manylinux_aarch64<br/>cp314-manylinux_ppc64le<br/>cp314-manylinux_s390x<br/>cp314-manylinux_armv7l<br/>cp314-manylinux_riscv64<br/>cp314-musllinux_aarch64<br/>cp314-musllinux_ppc64le<br/>cp314-musllinux_s390x<br/>cp314-musllinux_armv7l<br/>cp314-musllinux_riscv64<br><br>cp314t-manylinux_aarch64<br/>cp314t-manylinux_ppc64le<br/>cp314t-manylinux_s390x<br/>cp314t-manylinux_armv7l<br/>cp314t-manylinux_riscv64<br/>cp314t-musllinux_aarch64<br/>cp314t-musllinux_ppc64le<br/>cp314t-musllinux_s390x<br/>cp314t-musllinux_armv7l<br/>cp314t-musllinux_riscv64 | cp314-android_arm64_v8a<br/>cp314-android_x86_64 | cp314-ios_arm64_iphoneos<br/>cp314-ios_arm64_iphonesimulator<br/>cp314-ios_x86_64_iphonesimulator | |
| Python 3.15 | cp315-macosx_x86_64<br/>cp315-macosx_universal2<br/>cp315-macosx_arm64<br><br>cp315t-macosx_x86_64<br/>cp315t-macosx_universal2<br/>cp315t-macosx_arm64 | cp315-win_amd64<br/>cp315-win32<br/>cp315-win_arm64<br><br>cp315t-win_amd64<br/>cp315t-win32<br/>cp315t-win_arm64 | cp315-manylinux_x86_64<br/>cp315-manylinux_i686<br/>cp315-musllinux_x86_64<br/>cp315-musllinux_i686<br><br>cp315t-manylinux_x86_64<br/>cp315t-manylinux_i686<br/>cp315t-musllinux_x86_64<br/>cp315t-musllinux_i686 | cp315-manylinux_aarch64<br/>cp315-manylinux_ppc64le<br/>cp315-manylinux_s390x<br/>cp315-manylinux_armv7l<br/>cp315-manylinux_riscv64<br/>cp315-musllinux_aarch64<br/>cp315-musllinux_ppc64le<br/>cp315-musllinux_s390x<br/>cp315-musllinux_armv7l<br/>cp315-musllinux_riscv64<br><br>cp315t-manylinux_aarch64<br/>cp315t-manylinux_ppc64le<br/>cp315t-manylinux_s390x<br/>cp315t-manylinux_armv7l<br/>cp315t-manylinux_riscv64<br/>cp315t-musllinux_aarch64<br/>cp315t-musllinux_ppc64le<br/>cp315t-musllinux_s390x<br/>cp315t-musllinux_armv7l<br/>cp315t-musllinux_riscv64 | cp315-android_arm64_v8a<br/>cp315-android_x86_64 | cp315-ios_arm64_iphoneos<br/>cp315-ios_arm64_iphonesimulator<br/>cp315-ios_x86_64_iphonesimulator | | | Python 3.15 | cp315-macosx_x86_64<br/>cp315-macosx_universal2<br/>cp315-macosx_arm64<br><br>cp315t-macosx_x86_64<br/>cp315t-macosx_universal2<br/>cp315t-macosx_arm64 | cp315-win_amd64<br/>cp315-win32<br/>cp315-win_arm64<br><br>cp315t-win_amd64<br/>cp315t-win32<br/>cp315t-win_arm64 | cp315-manylinux_x86_64<br/>cp315-manylinux_i686<br/>cp315-musllinux_x86_64<br/>cp315-musllinux_i686<br><br>cp315t-manylinux_x86_64<br/>cp315t-manylinux_i686<br/>cp315t-musllinux_x86_64<br/>cp315t-musllinux_i686 | cp315-manylinux_aarch64<br/>cp315-manylinux_ppc64le<br/>cp315-manylinux_s390x<br/>cp315-manylinux_armv7l<br/>cp315-manylinux_riscv64<br/>cp315-musllinux_aarch64<br/>cp315-musllinux_ppc64le<br/>cp315-musllinux_s390x<br/>cp315-musllinux_armv7l<br/>cp315-musllinux_riscv64<br><br>cp315t-manylinux_aarch64<br/>cp315t-manylinux_ppc64le<br/>cp315t-manylinux_s390x<br/>cp315t-manylinux_armv7l<br/>cp315t-manylinux_riscv64<br/>cp315t-musllinux_aarch64<br/>cp315t-musllinux_ppc64le<br/>cp315t-musllinux_s390x<br/>cp315t-musllinux_armv7l<br/>cp315t-musllinux_riscv64 | cp315-android_arm64_v8a<br/>cp315-android_x86_64 | cp315-ios_arm64_iphoneos<br/>cp315-ios_arm64_iphonesimulator<br/>cp315-ios_x86_64_iphonesimulator | |
| PyPy3.9 v7.3 | pp39-macosx_x86_64<br/>pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64<br/>pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | | | PyPy3.9 v7.3 | pp39-macosx_x86_64<br/>pp39-macosx_arm64 | pp39-win_amd64 | pp39-manylinux_x86_64<br/>pp39-manylinux_i686 | pp39-manylinux_aarch64 | | | |
| PyPy3.10 v7.3 | pp310-macosx_x86_64<br/>pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64<br/>pp310-manylinux_i686 | pp310-manylinux_aarch64 | | | | | PyPy3.10 v7.3 | pp310-macosx_x86_64<br/>pp310-macosx_arm64 | pp310-win_amd64 | pp310-manylinux_x86_64<br/>pp310-manylinux_i686 | pp310-manylinux_aarch64 | | | |
@@ -481,11 +481,7 @@ files (from workspaces) are not supported.
are building GraalPy wheels, use `build` or `pip` as the build frontend are building GraalPy wheels, use `build` or `pip` as the build frontend
instead of `build[uv]` or `uv`. instead of `build[uv]` or `uv`.
On Android, the "pip" frontend is not supported. On Android and Pyodide, the "pip" frontend is not supported.
On Pyodide, `pyodide-build` is the default and only supported frontend; setting
another frontend produces a warning and uses `pyodide-build` instead. See
[Pyodide build frontend support](platforms.md#pyodide-build-frontend) for details.
You can specify extra arguments to pass to the build frontend using the You can specify extra arguments to pass to the build frontend using the
optional `args` option. optional `args` option.
@@ -1448,10 +1444,11 @@ Run shell commands to verify your wheels once they are built. Multiple commands
audit-requires = ["twine"] audit-requires = ["twine"]
audit-command = "twine check {wheel}" audit-command = "twine check {wheel}"
# Add an additional audit command using overrides, keeping the default abi3audit check # Add an additional audit command, keeping the default abi3audit check
[[tool.cibuildwheel.overrides]] [tool.cibuildwheel]
select = "*" inherit.audit-requires = "append"
inherit.audit-command = "append" inherit.audit-command = "append"
audit-requires = ["twine"]
audit-command = "twine check {wheel}" audit-command = "twine check {wheel}"
``` ```
@@ -1467,6 +1464,11 @@ Run shell commands to verify your wheels once they are built. Multiple commands
# Use twine check to validate wheel metadata # Use twine check to validate wheel metadata
CIBW_AUDIT_REQUIRES: "twine" CIBW_AUDIT_REQUIRES: "twine"
CIBW_AUDIT_COMMAND: "twine check {wheel}" CIBW_AUDIT_COMMAND: "twine check {wheel}"
# Add twine check to the default audit configuration
CIBW_AUDIT_REQUIRES: "twine"
CIBW_AUDIT_COMMAND: "twine check {wheel}"
CIBW_INHERIT: "audit-requires; audit-command"
``` ```
@@ -1914,14 +1916,14 @@ 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 | uv | pyodide-build | desc | | | build | pip | uv | desc |
|-------------|-------|--------|-------|---------------|----------------------------------------| |-------------|-------|--------|-------|----------------------------------------|
| -2 | `-qq` | `-qq` | `-qq` | | even more quiet, where supported | | -2 | `-qq` | `-qq` | `-qq` | even more quiet, where supported |
| -1 | `-q` | `-q` | `-q` | | quiet mode, where supported | | -1 | `-q` | `-q` | `-q` | quiet mode, where supported |
| 0 (default) | | | | | default for build tool | | 0 (default) | | | | default for build tool |
| 1 | | `-v` | | `-v` | print backend output | | 1 | | `-v` | | print backend output |
| 2 | `-v` | `-vv` | `-v` | `-vv` | print log messages e.g. resolving info | | 2 | `-v` | `-vv` | `-v` | print log messages e.g. resolving info |
| 3 | `-vv` | `-vvv` | `-vv` | | print even more debug info | | 3 | `-vv` | `-vvv` | `-vv` | print even more debug info |
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
-5
View File
@@ -188,11 +188,6 @@ repair-wheel-command = "pyodide auditwheel repair --libdir /path/to/libraries --
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. 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.
### Build frontend support {: #pyodide-build-frontend}
The pyodide platform builds wheels by shelling out to `pyodide build`, via the `pyodide-build` [`build-frontend`](options.md#build-frontend), which itself is a meta build frontend and passes through commands to pypa/build with specialised handling. This is the only supported frontend for this platform, and is used by default. A global [`build-frontend`](options.md#build-frontend) setting naming another frontend is ignored with a warning on this platform.
[`build-verbosity`](options.md#build-verbosity) is passed through to `pyodide build` as `-v`/`-vv`. It is capped at `-vv`. `pyodide build` has no `-vvv` flag.
## Android {: android} ## Android {: android}
+16 -16
View File
@@ -11,8 +11,8 @@ ref: working-examples
|-----------------------------------|----|----|:------| |-----------------------------------|----|----|:------|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. | | [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
| [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 |
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | The fundamental package for scientific computing with Python. |
| [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][] ![pyodide icon][] | The fundamental package for scientific computing with Python. |
| [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][] ![pyodide icon][] | The venerable Matplotlib, a Python library with C++ portions | | [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide 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. | | [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. |
@@ -48,9 +48,9 @@ ref: working-examples
| [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels | | [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels |
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy | | [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python | | [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
| [PyAV][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Pythonic bindings for FFmpeg's libraries. |
| [PyCryptodome][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A self-contained cryptographic library for Python |
| [Line Profiler][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Line-by-line profiling for Python | | [Line Profiler][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Line-by-line profiling for Python |
| [PyCryptodome][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A self-contained cryptographic library for Python |
| [PyAV][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Pythonic bindings for FFmpeg's libraries. |
| [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 |
@@ -77,12 +77,12 @@ ref: working-examples
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | Example pybind11 module built with a CMake-based build system | | [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide 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 |
| [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] ![pyodide icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
| [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][] ![pyodide icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson | | [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][] ![pyodide icon][] | Example pybind11 module built with a Python-based build system | | [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | Example pybind11 module built with a Python-based build system |
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
| [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` |
| [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. |
| [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 |
@@ -92,8 +92,8 @@ ref: working-examples
| [pillow-heif][] | ![github 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][] | ![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 |
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
| [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 | | [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 |
| [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. | | [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 |
| [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. |
@@ -102,16 +102,16 @@ ref: working-examples
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. | | [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
| [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][] ![pyodide icon][] | An example combining scikit-build and pybind11 | | [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] ![pyodide icon][] | An example combining scikit-build and pybind11 |
| [Arbor][] | ![github icon][] | ![apple icon][] ![linux icon][] | Arbor is a multi-compartment neuron simulation library; compatible with next-generation accelerators; best-practices applied to research software; focused on community-driven development. Includes a [small script](https://github.com/arbor-sim/arbor/blob/master/scripts/patchwheel.py) patching `rpath` in bundled libraries. |
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms | | [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
| [Arbor][] | ![github icon][] | ![apple icon][] ![linux icon][] | Arbor is a multi-compartment neuron simulation library; compatible with next-generation accelerators; best-practices applied to research software; focused on community-driven development. Includes a [small script](https://github.com/arbor-sim/arbor/blob/master/scripts/patchwheel.py) patching `rpath` in bundled libraries. |
| [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. | | [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. |
| [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. | | [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. |
| [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. |
| [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 |
| [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. |
| [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. |
| [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. |
| [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 | | [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. | | [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. |
@@ -122,8 +122,8 @@ ref: working-examples
[scikit-learn]: https://github.com/scikit-learn/scikit-learn [scikit-learn]: https://github.com/scikit-learn/scikit-learn
[duckdb]: https://github.com/duckdb/duckdb [duckdb]: https://github.com/duckdb/duckdb
[NumPy]: https://github.com/numpy/numpy
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq [pytorch-fairseq]: https://github.com/facebookresearch/fairseq
[NumPy]: https://github.com/numpy/numpy
[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 [Tornado]: https://github.com/tornadoweb/tornado
@@ -159,9 +159,9 @@ ref: working-examples
[Implicit]: https://github.com/benfred/implicit [Implicit]: https://github.com/benfred/implicit
[vispy]: https://github.com/vispy/vispy [vispy]: https://github.com/vispy/vispy
[coverage.py]: https://github.com/nedbat/coveragepy [coverage.py]: https://github.com/nedbat/coveragepy
[PyAV]: https://github.com/PyAV-Org/PyAV
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
[Line Profiler]: https://github.com/pyutils/line_profiler [Line Profiler]: https://github.com/pyutils/line_profiler
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
[PyAV]: https://github.com/PyAV-Org/PyAV
[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
@@ -188,12 +188,12 @@ ref: working-examples
[pybind11 cmake_example]: https://github.com/pybind/cmake_example [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
[sourmash]: https://github.com/sourmash-bio/sourmash
[tgcalls]: https://github.com/MarshalX/tgcalls [tgcalls]: https://github.com/MarshalX/tgcalls
[sourmash]: https://github.com/sourmash-bio/sourmash
[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 [pybind11 python_example]: https://github.com/pybind/python_example
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
[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
[abess]: https://github.com/abess-team/abess [abess]: https://github.com/abess-team/abess
[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
@@ -203,8 +203,8 @@ ref: working-examples
[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
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[iDynTree]: https://github.com/robotology/idyntree [iDynTree]: https://github.com/robotology/idyntree
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
[TgCrypto]: https://github.com/pyrogram/tgcrypto [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
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build [Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
@@ -213,16 +213,16 @@ ref: working-examples
[bx-python]: https://github.com/bxlab/bx-python [bx-python]: https://github.com/bxlab/bx-python
[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
[Arbor]: https://github.com/arbor-sim/arbor
[fathon]: https://github.com/stfbnc/fathon [fathon]: https://github.com/stfbnc/fathon
[Arbor]: https://github.com/arbor-sim/arbor
[clang-format]: https://github.com/ssciwr/clang-format-wheel [clang-format]: https://github.com/ssciwr/clang-format-wheel
[polaroid]: https://github.com/daggy1234/polaroid [polaroid]: https://github.com/daggy1234/polaroid
[ninja]: https://github.com/scikit-build/ninja-python-distributions [ninja]: https://github.com/scikit-build/ninja-python-distributions
[cf-units]: https://github.com/SciTools/cf-units [cf-units]: https://github.com/SciTools/cf-units
[etebase-py]: https://github.com/etesync/etebase-py [etebase-py]: https://github.com/etesync/etebase-py
[SiPM]: https://github.com/EdoPro98/SimSiPM [SiPM]: https://github.com/EdoPro98/SimSiPM
[numpythia]: https://github.com/scikit-hep/numpythia
[aalink]: https://github.com/artfwo/aalink [aalink]: https://github.com/artfwo/aalink
[numpythia]: https://github.com/scikit-hep/numpythia
[pyjet]: https://github.com/scikit-hep/pyjet [pyjet]: https://github.com/scikit-hep/pyjet
[ril]: https://github.com/Cryptex-github/ril-py [ril]: https://github.com/Cryptex-github/ril-py
[GSD]: https://github.com/glotzerlab/gsd [GSD]: https://github.com/glotzerlab/gsd
+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==4.1.1 pip3 install cibuildwheel==4.1.0
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==4.1.1 python3 -m pip install cibuildwheel==4.1.0
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==4.1.1 pip install cibuildwheel==4.1.0
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==4.1.1 python3 -m pip install --user cibuildwheel==4.1.0
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==4.1.1 python3 -m pip install --user cibuildwheel==4.1.0
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 x86_64/universal2 tests sudo softwareupdate --install-rosetta --agree-to-license # for x86_64/universal2 tests
pip3 install cibuildwheel==4.1.1 pip3 install cibuildwheel==4.1.0
cibuildwheel --output-dir wheelhouse cibuildwheel --output-dir wheelhouse
- store_artifacts: - store_artifacts:
path: wheelhouse/ path: wheelhouse/
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v4.1.1 uses: pypa/cibuildwheel@v4.1.0
env: env:
CIBW_PLATFORM: ${{ matrix.platform || 'auto' }} CIBW_PLATFORM: ${{ matrix.platform || 'auto' }}
CIBW_ARCHS: ${{ matrix.archs || 'auto' }} CIBW_ARCHS: ${{ matrix.archs || 'auto' }}
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v4.1.1 uses: pypa/cibuildwheel@v4.1.0
# env: # env:
# CIBW_SOME_OPTION: value # CIBW_SOME_OPTION: value
# ... # ...
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: Build wheels - name: Build wheels
run: pipx run cibuildwheel==4.1.1 run: pipx run cibuildwheel==4.1.0
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
platforms: all platforms: all
- name: Build wheels - name: Build wheels
uses: pypa/cibuildwheel@v4.1.1 uses: pypa/cibuildwheel@v4.1.0
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==4.1.1 - python -m pip install cibuildwheel==4.1.0
- 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==4.1.1 - py -m pip install cibuildwheel==4.1.0
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==4.1.1 - python3 -m pip install cibuildwheel==4.1.0
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==4.1.1 - python -m pip install cibuildwheel==4.1.0
# 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:
View File
+2 -56
View File
@@ -16,11 +16,9 @@ See sessions with `nox -l`
""" """
import os import os
import re
import shutil import shutil
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any
import nox import nox
@@ -65,52 +63,6 @@ def tests(session: nox.Session) -> None:
session.run("pytest", "test", "-x", "--durations", "0", "--timeout=2400", "test") session.run("pytest", "test", "-x", "--durations", "0", "--timeout=2400", "test")
# Packages held back for GraalPy until upstream fixes land. uv pip compile
# can't express a per-implementation split, so the compiled pin is patched:
# GraalPy (matching `graalpy_marker`) gets `held`, everything else
# (`other_marker`) tracks the freshly compiled version.
GRAALPY_HELD_BACK = (
# Newer pip breaks GraalPy on Windows.
{
"package": "pip",
"held": "26.0.1",
"graalpy_marker": 'implementation_name == "graalpy" and platform_system == "Windows"',
"other_marker": 'implementation_name != "graalpy" or platform_system != "Windows"',
},
# filelock >=3.30 imports errno.ENOTSUP, which GraalPy lacks (fix due ~2026-08).
{
"package": "filelock",
"held": "3.29.7",
"graalpy_marker": 'implementation_name == "graalpy"',
"other_marker": 'implementation_name != "graalpy"',
},
)
def _pin_graalpy_workarounds(output_file: Path) -> None:
text = output_file.read_text()
for pin in GRAALPY_HELD_BACK:
package = re.escape(pin["package"])
text = re.sub(
rf"^{package}==(?P<version>[^\s;]+)$",
f"{pin['package']}==\\g<version>; {pin['other_marker']}\n"
f"{pin['package']}=={pin['held']}; {pin['graalpy_marker']}",
text,
flags=re.MULTILINE,
)
output_file.write_text(text)
def _graalpy_python_versions(build_platforms: dict[str, Any]) -> set[str]:
"""Python minor versions (e.g. "3.12") that ship a GraalPy configuration."""
return {
".".join(config["version"].split(".")[:2])
for platform in build_platforms.values()
for config in platform["python_configurations"]
if config["identifier"].startswith("gp")
}
@nox.session(default=False, tags=["update"]) @nox.session(default=False, tags=["update"])
def update_constraints(session: nox.Session) -> None: def update_constraints(session: nox.Session) -> None:
""" """
@@ -127,9 +79,6 @@ def update_constraints(session: nox.Session) -> None:
env = os.environ.copy() env = os.environ.copy()
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}" env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
build_platforms = nox.project.load_toml(resources / "build-platforms.toml")
graalpy_versions = _graalpy_python_versions(build_platforms)
for minor_version in range(9, 16): for minor_version in range(9, 16):
python_version = f"3.{minor_version}" python_version = f"3.{minor_version}"
output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt" output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt"
@@ -143,14 +92,13 @@ def update_constraints(session: nox.Session) -> None:
f"--output-file={output_file}", f"--output-file={output_file}",
env=env, env=env,
) )
if python_version in graalpy_versions:
_pin_graalpy_workarounds(output_file)
shutil.copyfile( shutil.copyfile(
resources / "constraints-python315.txt", resources / "constraints-python315.txt",
resources / "constraints.txt", resources / "constraints.txt",
) )
build_platforms = nox.project.load_toml(resources / "build-platforms.toml")
pyodides = build_platforms["pyodide"]["python_configurations"] pyodides = build_platforms["pyodide"]["python_configurations"]
for pyodide in pyodides: for pyodide in pyodides:
python_version = ".".join(pyodide["version"].split(".")[:2]) python_version = ".".join(pyodide["version"].split(".")[:2])
@@ -228,9 +176,7 @@ def docs(session: nox.Session) -> None:
""" """
pyproject = nox.project.load_toml() pyproject = nox.project.load_toml()
session.install("-e.", *nox.project.dependency_groups(pyproject, "docs")) session.install("-e.", *nox.project.dependency_groups(pyproject, "docs"))
session.run( session.run("mkdocs", "serve" if session.interactive else "build", "--strict", *session.posargs)
"properdocs", "serve" if session.interactive else "build", "--strict", *session.posargs
)
@nox.session(default=False) @nox.session(default=False)
+2 -3
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "cibuildwheel" name = "cibuildwheel"
version = "4.1.1" version = "4.1.0"
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"
@@ -68,8 +68,7 @@ docs = [
"mkdocs-include-markdown-plugin==7.1.8", "mkdocs-include-markdown-plugin==7.1.8",
"mkdocs-intersphinx>=0.1.1; python_version >= '3.12'", "mkdocs-intersphinx>=0.1.1; python_version >= '3.12'",
"mkdocs-macros-plugin>=1.4.1", "mkdocs-macros-plugin>=1.4.1",
"properdocs==1.6.7", "mkdocs==1.6.1",
"properdocs-theme-readthedocs",
"pymdown-extensions", "pymdown-extensions",
"rich", "rich",
] ]
+27 -64
View File
@@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
import dataclasses
import json import json
import os import os
import subprocess import subprocess
@@ -13,16 +12,14 @@ from cibuildwheel.ci import detect_ci_provider
from cibuildwheel.options import CommandLineArguments, Options from cibuildwheel.options import CommandLineArguments, Options
from cibuildwheel.selector import EnableGroup from cibuildwheel.selector import EnableGroup
from cibuildwheel.typing import PLATFORMS from cibuildwheel.typing import PLATFORMS
from cibuildwheel.util.resources import PINNED_DOCKER_IMAGES
from cibuildwheel.venv import find_uv from cibuildwheel.venv import find_uv
from . import utils from . import utils
from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_enable_groups, get_platform from .utils import DEFAULT_CIBW_ENABLE, EMULATED_ARCHS, get_platform
TYPE_CHECKING = False TYPE_CHECKING = False
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Generator from collections.abc import Generator
from pathlib import Path
def pytest_addoption(parser: pytest.Parser) -> None: def pytest_addoption(parser: pytest.Parser) -> None:
@@ -77,19 +74,7 @@ def pytest_configure(config: pytest.Config) -> None:
os.environ["CIBW_PLATFORM"] = flag_platform os.environ["CIBW_PLATFORM"] = flag_platform
@dataclasses.dataclass(frozen=True) def docker_warmup(request: pytest.FixtureRequest) -> None:
class DockerWarmUpImage:
source_name: str
cached_name: str
def get_docker_warmup_images(request: pytest.FixtureRequest) -> list[DockerWarmUpImage] | None:
enable_groups = get_enable_groups()
# Check missing pre-installed interpreters are needed
enable_groups &= {EnableGroup.GraalPy, EnableGroup.PyPyEoL}
if not enable_groups:
return None
machine = request.config.getoption("--run-emulation", default=None) machine = request.config.getoption("--run-emulation", default=None)
if machine is None: if machine is None:
archs = {arch.value for arch in Architecture.auto_archs("linux")} archs = {arch.value for arch in Architecture.auto_archs("linux")}
@@ -101,7 +86,7 @@ def get_docker_warmup_images(request: pytest.FixtureRequest) -> list[DockerWarmU
# Only include architectures where there are missing pre-installed interpreters # Only include architectures where there are missing pre-installed interpreters
archs &= {"x86_64", "i686", "aarch64"} archs &= {"x86_64", "i686", "aarch64"}
if not archs: if not archs:
return None return
options = Options( options = Options(
platform="linux", platform="linux",
@@ -111,28 +96,17 @@ def get_docker_warmup_images(request: pytest.FixtureRequest) -> list[DockerWarmU
) )
build_options = options.build_options(None) build_options = options.build_options(None)
assert build_options.manylinux_images is not None assert build_options.manylinux_images is not None
images: list[DockerWarmUpImage] = [] assert build_options.musllinux_images is not None
for arch in archs: images = [build_options.manylinux_images[arch] for arch in archs] + [
source_name = build_options.manylinux_images[arch] build_options.musllinux_images[arch] for arch in archs
cached_name = source_name ]
if "@sha256:" in source_name:
cached_name = source_name.rsplit("@sha256:", 1)[0] + ":cibw_cache_fixture"
images.append(DockerWarmUpImage(source_name, cached_name))
if images:
return images
return None
def docker_warmup(images: list[DockerWarmUpImage], docker_warmup_config: Path) -> None:
command = ( command = (
"manylinux-interpreters ensure-all &&" "manylinux-interpreters ensure-all &&"
"cpython3.13 -m pip download -d /tmp setuptools wheel pytest" "cpython3.13 -m pip download -d /tmp setuptools wheel pytest"
) )
config_content = PINNED_DOCKER_IMAGES.read_text()
for image in images: for image in images:
config_content = config_content.replace(image.source_name, image.cached_name)
container_id = subprocess.run( container_id = subprocess.run(
["docker", "create", image.source_name, "bash", "-c", command], ["docker", "create", image, "bash", "-c", command],
text=True, text=True,
check=True, check=True,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
@@ -144,48 +118,37 @@ def docker_warmup(images: list[DockerWarmUpImage], docker_warmup_config: Path) -
).stdout.strip() ).stdout.strip()
assert exit_code == "0" assert exit_code == "0"
subprocess.run( subprocess.run(
["docker", "commit", container_id, image.cached_name], ["docker", "commit", container_id, image], check=True, stdout=subprocess.DEVNULL
check=True,
stdout=subprocess.DEVNULL,
) )
finally: finally:
subprocess.run(["docker", "rm", container_id], check=True, stdout=subprocess.DEVNULL) subprocess.run(["docker", "rm", container_id], check=True, stdout=subprocess.DEVNULL)
docker_warmup_config.write_text(config_content)
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)
def docker_warmup_fixture( def docker_warmup_fixture(
request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str
) -> Generator[None, None, None]: ) -> None:
# if we're in CI testing linux, let's warm-up docker images # if we're in CI testing linux, let's warm-up docker images
if detect_ci_provider() is None or get_platform() != "linux": if detect_ci_provider() is None or get_platform() != "linux":
images = None return None
elif request.config.getoption("--run-emulation", default=None) is not None: if request.config.getoption("--run-emulation", default=None) is not None:
# emulation tests only run one test in CI, caching the image only slows down the test # emulation tests only run one test in CI, caching the image only slows down the test
images = None return None
else:
images = get_docker_warmup_images(request)
if images is None:
yield None
return
if worker_id == "master": if worker_id == "master":
# not executing with multiple workers # not executing with multiple workers
# it might be unsafe to write to tmp_path_factory.getbasetemp().parent # it might be unsafe to write to tmp_path_factory.getbasetemp().parent
docker_warmup_config = tmp_path_factory.getbasetemp() / "docker_warmup.cfg" return docker_warmup(request)
docker_warmup(images, docker_warmup_config)
else:
# get the temp directory shared by all workers
root_tmp_dir = tmp_path_factory.getbasetemp().parent
docker_warmup_config = root_tmp_dir / "docker_warmup.cfg" # get the temp directory shared by all workers
with FileLock(str(docker_warmup_config) + ".lock"): root_tmp_dir = tmp_path_factory.getbasetemp().parent
if not docker_warmup_config.is_file():
docker_warmup(images, docker_warmup_config)
with pytest.MonkeyPatch.context() as monkeypatch: fn = root_tmp_dir / "warmup.done"
monkeypatch.setenv("CIBW_INTERNAL_PINNED_DOCKER_IMAGES", str(docker_warmup_config)) with FileLock(str(fn) + ".lock"):
yield None if not fn.is_file():
docker_warmup(request)
fn.write_text("done")
return None
@pytest.fixture(params=["pip", "build"]) @pytest.fixture(params=["pip", "build"])
@@ -194,8 +157,8 @@ def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
marks = {m.name for m in request.node.iter_markers()} marks = {m.name for m in request.node.iter_markers()}
platform = "pyodide" if "pyodide" in marks else get_platform() platform = "pyodide" if "pyodide" in marks else get_platform()
if platform == "pyodide": if platform == "pyodide" and frontend == "pip":
pytest.skip("pyodide only supports the pyodide-build frontend") pytest.skip("Can't use pip as build frontend for pyodide platform")
return {"CIBW_BUILD_FRONTEND": frontend} return {"CIBW_BUILD_FRONTEND": frontend}
@@ -213,10 +176,10 @@ def build_frontend_env(request: pytest.FixtureRequest) -> Generator[dict[str, st
else: else:
platform = get_platform() platform = get_platform()
if platform == "pyodide": if platform in {"pyodide", "ios", "android"} and frontend == "pip":
pytest.skip("pyodide only supports the pyodide-build frontend")
if platform in {"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 in {"build[uv]", "uv"}:
pytest.skip("Can't use uv with pyodide yet")
uv_path = find_uv() uv_path = find_uv()
if uv_path is None and frontend in {"build[uv]", "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")
+1 -1
View File
@@ -690,7 +690,7 @@ def test_xbuild_files(tmp_path: Path, capfd: pytest.CaptureFixture[str]) -> None
add_env={ add_env={
**cp313_env, **cp313_env,
# TODO: remove this once there are official Android NumPy wheels on PyPI. # TODO: remove this once there are official Android NumPy wheels on PyPI.
"PIP_EXTRA_INDEX_URL": "https://chaquo.com/pypi-upstream", "PIP_EXTRA_INDEX_URL": "https://chaquo.com/pypi-test",
"CIBW_ARCHS": "all", # Include both native and non-native archs. "CIBW_ARCHS": "all", # Include both native and non-native archs.
"CIBW_TEST_COMMAND": f"python -c '{script}'", "CIBW_TEST_COMMAND": f"python -c '{script}'",
}, },
+1 -1
View File
@@ -50,7 +50,7 @@ def test(tmp_path: Path) -> None:
"""python -c "import pathlib, sys; pathlib.Path('{project}/pythonversion_bb.txt').write_text(sys.version)" && """ """python -c "import pathlib, sys; pathlib.Path('{project}/pythonversion_bb.txt').write_text(sys.version)" && """
f'''python -c "import pathlib, sys; pathlib.Path('{{project}}/pythonprefix_bb.txt').write_text({SYS_PREFIX})"''' f'''python -c "import pathlib, sys; pathlib.Path('{{project}}/pythonprefix_bb.txt').write_text({SYS_PREFIX})"'''
) )
frontend = "pyodide-build" if utils.get_platform() == "pyodide" else "build" frontend = "build"
if utils.get_platform() != "pyodide": if utils.get_platform() != "pyodide":
before_build = f"python -m pip install setuptools && {before_build}" before_build = f"python -m pip install setuptools && {before_build}"
frontend = f"{frontend};args: --no-isolation" frontend = f"{frontend};args: --no-isolation"
+3 -13
View File
@@ -15,17 +15,7 @@ if TYPE_CHECKING:
"frontend_name", "frontend_name",
[ [
pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")), pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")),
pytest.param( "build",
"build",
marks=utils.skip_if_pyodide("pyodide only supports the pyodide-build frontend"),
),
pytest.param(
"pyodide-build",
marks=pytest.mark.skipif(
utils.get_platform() != "pyodide",
reason="pyodide-build frontend is only valid on pyodide",
),
),
], ],
) )
def test_build_frontend_args( def test_build_frontend_args(
@@ -37,7 +27,7 @@ def test_build_frontend_args(
# the build will fail because the frontend is called with '-h' - it prints the help message # the build will fail because the frontend is called with '-h' - it prints the help message
add_env = {"CIBW_BUILD_FRONTEND": f"{frontend_name}; args: -h"} add_env = {"CIBW_BUILD_FRONTEND": f"{frontend_name}; args: -h"}
if frontend_name == "pyodide-build": if utils.get_platform() == "pyodide":
add_env["TERM"] = "dumb" # disable color / style add_env["TERM"] = "dumb" # disable color / style
add_env["NO_COLOR"] = "1" add_env["NO_COLOR"] = "1"
with pytest.raises(subprocess.CalledProcessError): with pytest.raises(subprocess.CalledProcessError):
@@ -50,7 +40,7 @@ def test_build_frontend_args(
if frontend_name == "pip": if frontend_name == "pip":
assert "Usage:" in captured.out assert "Usage:" in captured.out
assert "Wheel Options:" in captured.out assert "Wheel Options:" in captured.out
elif frontend_name == "pyodide-build": elif utils.get_platform() == "pyodide":
assert "Usage: pyodide build" in captured.out assert "Usage: pyodide build" in captured.out
else: else:
assert "usage:" in captured.out assert "usage:" in captured.out
+1 -7
View File
@@ -12,10 +12,7 @@ basic_project = test_projects.new_c_project()
def test_podman( def test_podman(
tmp_path: Path, tmp_path: Path, capfd: pytest.CaptureFixture[str], request: pytest.FixtureRequest
capfd: pytest.CaptureFixture[str],
request: pytest.FixtureRequest,
monkeypatch: pytest.MonkeyPatch,
) -> None: ) -> 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")
@@ -23,9 +20,6 @@ def test_podman(
if not request.config.getoption("--run-podman"): if not request.config.getoption("--run-podman"):
pytest.skip("needs --run-podman option to run") pytest.skip("needs --run-podman option to run")
# we can't use images cached in the docker_warmup_fixture autouse fixture
monkeypatch.delenv("CIBW_INTERNAL_PINNED_DOCKER_IMAGES", raising=False)
project_dir = tmp_path / "project" project_dir = tmp_path / "project"
basic_project.generate(project_dir) basic_project.generate(project_dir)
-18
View File
@@ -1,14 +1,10 @@
import tomllib import tomllib
from pathlib import Path
import pytest
from packaging.version import Version from packaging.version import Version
from cibuildwheel.extra import Printable, dump_python_configurations from cibuildwheel.extra import Printable, dump_python_configurations
from cibuildwheel.util import resources from cibuildwheel.util import resources
OPTIONS_MD = Path(__file__).parents[1] / "docs" / "options.md"
def test_compare_configs() -> None: def test_compare_configs() -> None:
txt = resources.BUILD_PLATFORMS.read_text() txt = resources.BUILD_PLATFORMS.read_text()
@@ -22,20 +18,6 @@ def test_compare_configs() -> None:
assert new_txt == txt assert new_txt == txt
@pytest.mark.skipif(not OPTIONS_MD.is_file(), reason="docs/options.md not present")
def test_all_identifiers_in_docs_table() -> None:
# The build-id table in docs/options.md is hand-maintained; this guards
# against forgetting an identifier when build-platforms.toml changes.
docs = OPTIONS_MD.read_text()
identifiers = [
config["identifier"]
for configs in resources.read_all_configs().values()
for config in configs
]
missing = [i for i in identifiers if i not in docs]
assert not missing, f"Missing from docs/options.md build-id table: {missing}"
def test_dump_with_Version() -> None: def test_dump_with_Version() -> None:
# MyPy doesn't understand deeply nested dicts correctly # MyPy doesn't understand deeply nested dicts correctly
example: dict[str, dict[str, list[dict[str, Printable]]]] = { example: dict[str, dict[str, list[dict[str, Printable]]]] = {
+11 -11
View File
@@ -173,19 +173,19 @@ def test_empty_selector(monkeypatch: pytest.MonkeyPatch) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("architecture", "image", "full_image"), ("architecture", "image", "full_image"),
[ [
("x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64@*"), ("x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64:*"),
("x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64@*"), ("x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"),
("x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64@*"), ("x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64:*"),
("x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64@*"), ("x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64:*"),
("x86_64", "custom_image", "custom_image"), ("x86_64", "custom_image", "custom_image"),
("i686", None, "quay.io/pypa/manylinux_2_28_i686@*"), ("i686", None, "quay.io/pypa/manylinux_2_28_i686:*"),
("i686", "manylinux2014", "quay.io/pypa/manylinux2014_i686@*"), ("i686", "manylinux2014", "quay.io/pypa/manylinux2014_i686:*"),
("i686", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_i686@*"), ("i686", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_i686:*"),
("i686", "custom_image", "custom_image"), ("i686", "custom_image", "custom_image"),
("pypy_x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64@*"), ("pypy_x86_64", None, "quay.io/pypa/manylinux_2_28_x86_64:*"),
("pypy_x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64@*"), ("pypy_x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"),
("pypy_x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64@*"), ("pypy_x86_64", "manylinux_2_28", "quay.io/pypa/manylinux_2_28_x86_64:*"),
("pypy_x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64@*"), ("pypy_x86_64", "manylinux_2_34", "quay.io/pypa/manylinux_2_34_x86_64:*"),
("pypy_x86_64", "custom_image", "custom_image"), ("pypy_x86_64", "custom_image", "custom_image"),
], ],
) )
@@ -1,3 +1,5 @@
"""Tests for reading and resolving configuration options."""
from __future__ import annotations from __future__ import annotations
import shlex import shlex
@@ -5,6 +7,7 @@ from typing import Any, cast
import pytest import pytest
from cibuildwheel import errors
from cibuildwheel.options import ( from cibuildwheel.options import (
EnvironmentFormat, EnvironmentFormat,
InheritRule, InheritRule,
@@ -472,7 +475,11 @@ test-command = "pyproject-override"
) )
with pytest.raises(OptionsReaderError): with pytest.raises(OptionsReaderError):
OptionsReader(config_file_path=pyproject_toml, platform=cast("Any", platform), env={}) print(
OptionsReader(
config_file_path=pyproject_toml, platform=cast("Any", platform), env={}
).overrides
)
def test_config_settings(tmp_path: Path) -> None: def test_config_settings(tmp_path: Path) -> None:
@@ -549,6 +556,112 @@ before-all = ["override2"]
) )
def test_global_inherit(tmp_path: Path) -> None:
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
"""\
[tool.cibuildwheel]
inherit = {audit-command = "append"}
audit-command = "twine check {wheel}"
"""
)
options_reader = OptionsReader(pyproject_toml, platform="linux", env={})
assert (
options_reader.get("audit-command", option_format=ListFormat(" && "))
== "abi3audit --strict --report {abi3_wheel} && twine check {wheel}"
)
def test_platform_inherit(tmp_path: Path) -> None:
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
"""\
[tool.cibuildwheel]
before-all = "global"
[tool.cibuildwheel.linux]
inherit = {before-all = "prepend"}
before-all = "linux"
"""
)
options_reader = OptionsReader(pyproject_toml, platform="linux", env={})
assert options_reader.get("before-all", option_format=ListFormat(" && ")) == "linux && global"
def test_environment_inherit(tmp_path: Path) -> None:
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
"""\
[tool.cibuildwheel]
before-all = "config"
"""
)
options_reader = OptionsReader(
pyproject_toml,
platform="linux",
env={
"CIBW_BEFORE_ALL": "env",
"CIBW_BEFORE_ALL_LINUX": "linux-env",
# A key without a value defaults to append.
"CIBW_INHERIT": "before-all; before-all-linux: prepend",
},
)
assert (
options_reader.get("before-all", option_format=ListFormat(" && "))
== "linux-env && config && env"
)
def test_environment_inherit_none_overrides_default_rule(tmp_path: Path) -> None:
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
"""\
[tool.cibuildwheel]
enable = ["cpython-freethreading"]
"""
)
options_reader = OptionsReader(
pyproject_toml,
platform="linux",
env={"CIBW_ENABLE": "pypy", "CIBW_INHERIT": "enable: none"},
)
assert (
options_reader.get(
"enable", option_format=ListFormat(" "), default_env_rule=InheritRule.APPEND
)
== "pypy"
)
def test_invalid_config_inherit_rule(tmp_path: Path) -> None:
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
"""\
[tool.cibuildwheel]
inherit = {before-all = "invalid"}
"""
)
with pytest.raises(OptionsReaderError, match="must contain only"):
OptionsReader(pyproject_toml, platform="linux", env={})
def test_invalid_environment_inherit_rule() -> None:
options_reader = OptionsReader(platform="linux", env={"CIBW_INHERIT": "before-all: invalid"})
with pytest.raises(
errors.ConfigurationError, match="Failed to parse CIBW_INHERIT environment variable"
):
options_reader.get("before-all", option_format=ListFormat(" && "))
def test_audit_command_option(tmp_path: Path, platform: PlatformName) -> None: def test_audit_command_option(tmp_path: Path, platform: PlatformName) -> None:
pyproject_toml: Path = tmp_path / "pyproject.toml" pyproject_toml: Path = tmp_path / "pyproject.toml"
pyproject_toml.write_text( pyproject_toml.write_text(
+1 -120
View File
@@ -39,8 +39,6 @@ TYPE_CHECKING = False
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Callable, Sequence from collections.abc import Callable, Sequence
from cibuildwheel.typing import PlatformName
PYPROJECT_1 = """ PYPROJECT_1 = """
[tool.cibuildwheel] [tool.cibuildwheel]
build = ["cp38-*", "cp313-*"] build = ["cp38-*", "cp313-*"]
@@ -482,93 +480,6 @@ def test_build_frontend_option(
assert parsed_build_frontend.args == () assert parsed_build_frontend.args == ()
def test_pyodide_build_frontend_default(tmp_path: Path) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
tmp_path.joinpath("pyproject.toml").write_text("[tool.cibuildwheel]\n")
options = Options(platform="pyodide", command_line_arguments=args, env={})
build_frontend = options.build_options(identifier=None).build_frontend
assert build_frontend.name == "pyodide-build"
assert build_frontend.args == []
def test_pyodide_build_frontend_args(tmp_path: Path) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
tmp_path.joinpath("pyproject.toml").write_text(
textwrap.dedent(
"""\
[tool.cibuildwheel.pyodide]
build-frontend = {name = "pyodide-build", args = ["--exports=whole_archive"]}
"""
)
)
options = Options(platform="pyodide", command_line_arguments=args, env={})
build_frontend = options.build_options(identifier=None).build_frontend
assert build_frontend.name == "pyodide-build"
assert build_frontend.args == ["--exports=whole_archive"]
@pytest.mark.parametrize(
"build_frontend_str",
["default", "pip", "build", "build[uv]", "uv"],
)
def test_pyodide_global_build_frontend_coerced(tmp_path: Path, build_frontend_str: str) -> None:
"""A global non-pyodide frontend setting is coerced to pyodide-build, not an error."""
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
tmp_path.joinpath("pyproject.toml").write_text(
textwrap.dedent(
f"""\
[tool.cibuildwheel]
build-frontend = "{build_frontend_str}"
"""
)
)
options = Options(platform="pyodide", command_line_arguments=args, env={})
build_frontend = options.build_options(identifier=None).build_frontend
assert build_frontend.name == "pyodide-build"
@pytest.mark.parametrize(
("platform", "build_frontend_str"),
[
("linux", "pyodide-build"),
("macos", "pyodide-build"),
("windows", "pyodide-build"),
("android", "pyodide-build"),
("ios", "pyodide-build"),
],
)
def test_build_frontend_platform_mismatch(
tmp_path: Path, platform: PlatformName, build_frontend_str: str
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
tmp_path.joinpath("pyproject.toml").write_text(
textwrap.dedent(
f"""\
[tool.cibuildwheel]
build-frontend = "{build_frontend_str}"
"""
)
)
options = Options(platform=platform, command_line_arguments=args, env={})
with pytest.raises(errors.ConfigurationError):
options.build_options(identifier=None)
def test_override_inherit_environment(tmp_path: Path) -> None: def test_override_inherit_environment(tmp_path: Path) -> None:
args = CommandLineArguments.defaults() args = CommandLineArguments.defaults()
args.package_dir = tmp_path args.package_dir = tmp_path
@@ -752,15 +663,10 @@ def test_deprecated_image(
("build", 3, ["-Ca", "-Cb", "-1", "-vv"]), ("build", 3, ["-Ca", "-Cb", "-1", "-vv"]),
("build[uv]", 3, ["-Ca", "-Cb", "-1", "-vv"]), ("build[uv]", 3, ["-Ca", "-Cb", "-1", "-vv"]),
("uv", 3, ["-Ca", "-Cb", "-1", "-vv"]), ("uv", 3, ["-Ca", "-Cb", "-1", "-vv"]),
("pyodide-build", -1, ["-Ca", "-Cb", "-1"]),
("pyodide-build", 0, ["-Ca", "-Cb", "-1"]),
("pyodide-build", 1, ["-Ca", "-Cb", "-1", "-v"]),
("pyodide-build", 2, ["-Ca", "-Cb", "-1", "-vv"]),
("pyodide-build", 3, ["-Ca", "-Cb", "-1", "-vv"]),
], ],
) )
def test_get_build_frontend_extra_flags( def test_get_build_frontend_extra_flags(
frontend: Literal["pip", "build", "build[uv]", "uv", "pyodide-build"], frontend: Literal["pip", "build", "build[uv]"],
verbosity: int, verbosity: int,
result: list[str], result: list[str],
monkeypatch: pytest.MonkeyPatch, monkeypatch: pytest.MonkeyPatch,
@@ -852,31 +758,6 @@ def test_test_runtime_handling(
assert local.test_runtime.args == expected_args assert local.test_runtime.args == expected_args
@pytest.mark.parametrize(
("platform", "platform_envvar"),
[
("android", "CIBW_TEST_RUNTIME_ANDROID"),
("ios", "CIBW_TEST_RUNTIME_IOS"),
],
)
def test_test_runtime_platform_environment(
tmp_path: Path, platform: PlatformName, platform_envvar: str
) -> None:
args = CommandLineArguments.defaults()
args.package_dir = tmp_path
options = Options(
platform=platform,
command_line_arguments=args,
env={
"CIBW_TEST_RUNTIME": "args: --global",
platform_envvar: "args: --platform-specific",
},
)
assert options.build_options(None).test_runtime.args == ["--platform-specific"]
@pytest.mark.parametrize( @pytest.mark.parametrize(
("definition", "expected"), ("definition", "expected"),
[ [
+53 -11
View File
@@ -11,6 +11,7 @@ from cibuildwheel.util.file import copy_test_sources, remove_on_error
from cibuildwheel.util.helpers import ( from cibuildwheel.util.helpers import (
FlexibleVersion, FlexibleVersion,
format_safe, format_safe,
parse_arbitrary_key_value_string,
parse_key_value_string, parse_key_value_string,
prepare_command, prepare_command,
unwrap, unwrap,
@@ -218,20 +219,61 @@ def test_parse_key_value_string_unknown_name() -> None:
with pytest.raises(ValueError, match=r"Failed to parse 'key: value'. Unknown field name 'key'"): with pytest.raises(ValueError, match=r"Failed to parse 'key: value'. Unknown field name 'key'"):
parse_key_value_string("key: value") parse_key_value_string("key: value")
# Unknown fields can be enabled by passing "*".
assert parse_key_value_string( def test_parse_arbitrary_key_value_string_basic() -> None:
"key: value", assert parse_arbitrary_key_value_string("before-test: append; after-test: prepend") == {
kw_arg_names=["*"], "before-test": ["append"],
) == { "after-test": ["prepend"],
"key": ["value"],
} }
assert parse_key_value_string(
"key1: value1a value1b; key2: value2", def test_parse_arbitrary_key_value_string_multiple_values() -> None:
kw_arg_names=["*"], assert parse_arbitrary_key_value_string(
"package1: some/header.h some/library.a; package2: other/header.h"
) == { ) == {
"key1": ["value1a", "value1b"], "package1": ["some/header.h", "some/library.a"],
"key2": ["value2"], "package2": ["other/header.h"],
}
def test_parse_arbitrary_key_value_string_keys_without_values_default() -> None:
assert parse_arbitrary_key_value_string(
"before-build; before-test: prepend", default_value="append"
) == {
"before-build": ["append"],
"before-test": ["prepend"],
}
def test_parse_arbitrary_key_value_string_keys_without_values_no_default() -> None:
with pytest.raises(ValueError, match="No value specified"):
parse_arbitrary_key_value_string("before-build")
def test_parse_arbitrary_key_value_string_empty() -> None:
assert parse_arbitrary_key_value_string("") == {}
def test_parse_arbitrary_key_value_string_duplicate_keys() -> None:
assert parse_arbitrary_key_value_string("key: val1; key: val2") == {
"key": ["val1", "val2"],
}
def test_parse_arbitrary_key_value_string_key_only_with_colon() -> None:
assert parse_arbitrary_key_value_string("key:") == {"key": []}
def test_parse_arbitrary_key_value_string_quoted_values() -> None:
assert parse_arbitrary_key_value_string('key: "hello world"') == {"key": ["hello world"]}
def test_parse_arbitrary_key_value_string_multiple_bare_keys_with_default() -> None:
"""works, but should remain undocumented"""
assert parse_arbitrary_key_value_string("a b c", default_value="yes") == {
"a": ["yes"],
"b": ["yes"],
"c": ["yes"],
} }
-60
View File
@@ -1,60 +0,0 @@
import os
import sys
from pathlib import Path
import pytest
import cibuildwheel.venv
from cibuildwheel.venv import activate_virtualenv, find_uv, virtualenv
def test_activate_virtualenv(tmp_path: Path) -> None:
venv_path = tmp_path / "venv"
env = activate_virtualenv(venv_path, env={"PATH": "/usr/bin"})
paths = env["PATH"].split(os.pathsep)
if sys.platform == "win32":
assert paths[:2] == [str(venv_path), str(venv_path / "Scripts")]
else:
assert paths[0] == str(venv_path / "bin")
assert paths[-1] == "/usr/bin"
assert env["VIRTUAL_ENV"] == str(venv_path)
def test_activate_virtualenv_base_python_bin_dir(tmp_path: Path) -> None:
venv_path = tmp_path / "venv"
base_bin = tmp_path / "base" / "bin"
env = activate_virtualenv(venv_path, env={"PATH": "/usr/bin"}, base_python_bin_dir=base_bin)
paths = env["PATH"].split(os.pathsep)
# the base interpreter's bin dir comes right after the venv, so scripts
# like python3-config resolve to the matching interpreter (see #2021)
if sys.platform == "win32":
assert paths[:3] == [str(venv_path), str(venv_path / "Scripts"), str(base_bin)]
else:
assert paths[:2] == [str(venv_path / "bin"), str(base_bin)]
assert paths[-1] == "/usr/bin"
@pytest.mark.skipif(sys.platform == "win32", reason="POSIX-only behavior")
@pytest.mark.skipif(find_uv() is None, reason="requires uv")
def test_virtualenv_puts_base_python_bin_dir_on_path(tmp_path: Path) -> None:
version = "{}.{}".format(*sys.version_info[:2])
venv_path = tmp_path / "venv"
env = virtualenv(
version, Path(sys.executable), venv_path, None, use_uv=True, env={"PATH": "/usr/bin"}
)
paths = env["PATH"].split(os.pathsep)
assert paths == [str(venv_path / "bin"), str(Path(sys.executable).parent), "/usr/bin"]
@pytest.mark.skipif(find_uv() is None, reason="requires uv")
def test_virtualenv_no_base_python_bin_dir_on_windows(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setattr(cibuildwheel.venv, "_IS_WIN", True)
version = "{}.{}".format(*sys.version_info[:2])
venv_path = tmp_path / "venv"
env = virtualenv(
version, Path(sys.executable), venv_path, None, use_uv=True, env={"PATH": "/usr/bin"}
)
paths = env["PATH"].split(os.pathsep)
assert str(Path(sys.executable).parent) not in paths