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