Compare commits
105
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50fef6ffbf | ||
|
|
b1ed7bb3bc | ||
|
|
ca08f5fbcf | ||
|
|
229029e112 | ||
|
|
3294577c17 | ||
|
|
8f51efbc3e | ||
|
|
ebdbb3cbd5 | ||
|
|
3a30bec9ef | ||
|
|
126b81916d | ||
|
|
9abea5b73b | ||
|
|
170e7aaeb9 | ||
|
|
5b570a2451 | ||
|
|
ffd7dddcc7 | ||
|
|
b0b13d3a16 | ||
|
|
b1781e4606 | ||
|
|
3580374b18 | ||
|
|
c6dd39bd83 | ||
|
|
dd8fe86308 | ||
|
|
2e12f05d5e | ||
|
|
bd033a4447 | ||
|
|
9d023cf77a | ||
|
|
8a69dbd9d4 | ||
|
|
147de6f4f7 | ||
|
|
e217e44661 | ||
|
|
871ef6b506 | ||
|
|
fac72f024a | ||
|
|
d4c332104d | ||
|
|
5af5df4e4f | ||
|
|
6c5cf87871 | ||
|
|
46f4108f23 | ||
|
|
1da439f8dc | ||
|
|
7af9d039fb | ||
|
|
de84624d70 | ||
|
|
cac121a67d | ||
|
|
604da878cb | ||
|
|
eaf0051162 | ||
|
|
8dcf71e02d | ||
|
|
92f0142a3e | ||
|
|
6c8347f465 | ||
|
|
a4d24056ef | ||
|
|
7e5a838a63 | ||
|
|
19e1b8a4b0 | ||
|
|
73581ae579 | ||
|
|
f21ff5e84c | ||
|
|
973946b172 | ||
|
|
5ea40e6ff3 | ||
|
|
6a36f6494b | ||
|
|
31de15bcd9 | ||
|
|
3179fd215a | ||
|
|
184d4e1280 | ||
|
|
08165ffeed | ||
|
|
9bb03835e5 | ||
|
|
2552303ff3 | ||
|
|
5b74582a72 | ||
|
|
4470eb0dd9 | ||
|
|
8bda260d3a | ||
|
|
5b5a95bdc2 | ||
|
|
561fa32683 | ||
|
|
70913f0a49 | ||
|
|
f49397f151 | ||
|
|
c1b8a12cd5 | ||
|
|
932529cab1 | ||
|
|
70fb1c4a1a | ||
|
|
405a475ac7 | ||
|
|
78da7bafcc | ||
|
|
8d86d3122b | ||
|
|
89a5cfe272 | ||
|
|
8d5d84e0fc | ||
|
|
4ada77dea4 | ||
|
|
829441f4a0 | ||
|
|
a8d190a111 | ||
|
|
bf817c6dc8 | ||
|
|
384c8d5c82 | ||
|
|
c37e5a2d13 | ||
|
|
130fdd2548 | ||
|
|
ed120540d9 | ||
|
|
6c6e0f6ba5 | ||
|
|
877d3bf649 | ||
|
|
21e9ef1800 | ||
|
|
c333b131d3 | ||
|
|
4c2ed1e632 | ||
|
|
9f2a3cb67c | ||
|
|
687406f664 | ||
|
|
2e6b11e10c | ||
|
|
b713086763 | ||
|
|
8f574d107b | ||
|
|
97da90432e | ||
|
|
67ee9dda92 | ||
|
|
ba8be0d988 | ||
|
|
90dd47640f | ||
|
|
b61324914b | ||
|
|
3992d5719c | ||
|
|
345467c6cf | ||
|
|
791e41cfec | ||
|
|
9d5f5e60b8 | ||
|
|
1b354cfa63 | ||
|
|
d1a4c9c074 | ||
|
|
78bca57cb4 | ||
|
|
f8894e67f5 | ||
|
|
666a2c3f1a | ||
|
|
15447bd591 | ||
|
|
678ef21647 | ||
|
|
e82b1bfc44 | ||
|
|
ced16da65f | ||
|
|
63daa02352 |
@@ -1,9 +1,10 @@
|
|||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
osx-python3.9:
|
osx-python3.12:
|
||||||
macos:
|
macos:
|
||||||
xcode: 12.5.1
|
xcode: 15.4.0
|
||||||
|
resource_class: macos.m1.medium.gen1
|
||||||
environment:
|
environment:
|
||||||
PYTHON: python3
|
PYTHON: python3
|
||||||
steps:
|
steps:
|
||||||
@@ -17,9 +18,9 @@ jobs:
|
|||||||
command: venv/bin/python ./bin/run_tests.py
|
command: venv/bin/python ./bin/run_tests.py
|
||||||
no_output_timeout: 30m
|
no_output_timeout: 30m
|
||||||
|
|
||||||
linux-python3.9:
|
linux-python3.12:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/python:3.9
|
- image: cimg/python:3.12
|
||||||
environment:
|
environment:
|
||||||
PYTHON: python3
|
PYTHON: python3
|
||||||
# Temporarily restrict the tests that are run on CircleCI to prevent
|
# Temporarily restrict the tests that are run on CircleCI to prevent
|
||||||
@@ -61,6 +62,6 @@ workflows:
|
|||||||
version: 2
|
version: 2
|
||||||
all-tests:
|
all-tests:
|
||||||
jobs:
|
jobs:
|
||||||
- osx-python3.9
|
- osx-python3.12
|
||||||
- linux-python3.9
|
- linux-python3.12
|
||||||
- linux-aarch64
|
- linux-aarch64
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
set -o errexit
|
set -o errexit
|
||||||
set -o xtrace
|
set -o xtrace
|
||||||
|
|
||||||
|
if [ "$(uname -s)" == "Darwin" ]; then
|
||||||
|
sudo softwareupdate --install-rosetta --agree-to-license
|
||||||
|
fi
|
||||||
|
|
||||||
$PYTHON --version
|
$PYTHON --version
|
||||||
$PYTHON -m pip --version
|
$PYTHON -m venv venv
|
||||||
$PYTHON -m virtualenv -p "$PYTHON" venv
|
venv/bin/python -m pip install -U pip
|
||||||
venv/bin/python -m pip install -e ".[dev]"
|
venv/bin/python -m pip install -e ".[dev]"
|
||||||
venv/bin/python -m pip freeze
|
venv/bin/python -m pip freeze
|
||||||
venv/bin/python --version
|
venv/bin/python --version
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"problemMatcher": [
|
|
||||||
{
|
|
||||||
"severity": "warning",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "^([^:]+):(\\d+):(\\d+): ([A-DF-Z]\\d+): \\033\\[[\\d;]+m([^\\033]+).*$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 2,
|
|
||||||
"column": 3,
|
|
||||||
"code": 4,
|
|
||||||
"message": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"owner": "pylint-warning"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "^([^:]+):(\\d+):(\\d+): (E\\d+): \\033\\[[\\d;]+m([^\\033]+).*$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 2,
|
|
||||||
"column": 3,
|
|
||||||
"code": 4,
|
|
||||||
"message": 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"owner": "pylint-error"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -28,9 +28,12 @@ jobs:
|
|||||||
needs: [dist]
|
needs: [dist]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.event_name == 'release' && github.event.action == 'published'
|
if: github.event_name == 'release' && github.event.action == 'published'
|
||||||
environment: pypi
|
environment:
|
||||||
|
name: pypi
|
||||||
|
url: https://pypi.org/p/cibuildwheel
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
@@ -39,4 +42,9 @@ jobs:
|
|||||||
path: dist
|
path: dist
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Generate artifact attestation for sdist and wheel
|
||||||
|
uses: actions/attest-build-provenance@6149ea5740be74af77f260b9db67e633f6b0a9a1 # v1.4.2
|
||||||
|
with:
|
||||||
|
subject-path: "dist/cibuildwheel-*"
|
||||||
|
|
||||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
|||||||
+69
-21
@@ -22,18 +22,17 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
- uses: pre-commit/action@v3.0.1
|
- uses: pre-commit/action@v3.0.1
|
||||||
- name: Check manifest
|
- name: Check manifest
|
||||||
run: pipx run nox -s check_manifest
|
run: pipx run --python "${{ steps.python.outputs.python-path }}" nox -s check_manifest
|
||||||
- name: PyLint checks
|
- name: PyLint checks
|
||||||
run: |
|
run: pipx run --python "${{ steps.python.outputs.python-path }}" nox -s pylint -- --output-format=github
|
||||||
echo "::add-matcher::$GITHUB_WORKSPACE/.github/matchers/pylint.json"
|
|
||||||
pipx run nox -s pylint
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test cibuildwheel on ${{ matrix.os }} (${{ matrix.python_version }})
|
name: Test on ${{ matrix.os }} (${{ matrix.python_version }})
|
||||||
needs: lint
|
needs: lint
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -51,16 +50,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python_version }}
|
python-version: ${{ matrix.python_version }}
|
||||||
|
|
||||||
# Install podman on this CI instance for podman tests on linux
|
- uses: yezz123/setup-uv@v4
|
||||||
# Snippet from: https://github.com/redhat-actions/podman-login/blob/main/.github/workflows/example.yml
|
|
||||||
- name: Install latest podman
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
. /etc/os-release
|
|
||||||
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
|
|
||||||
curl -sSfL "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key" | sudo apt-key add -
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install podman
|
|
||||||
|
|
||||||
# free some space to prevent reaching GHA disk space limits
|
# free some space to prevent reaching GHA disk space limits
|
||||||
- name: Clean docker images
|
- name: Clean docker images
|
||||||
@@ -71,7 +61,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install ".[test]"
|
uv pip install --system ".[test]"
|
||||||
|
|
||||||
- name: Generate a sample project
|
- name: Generate a sample project
|
||||||
run: |
|
run: |
|
||||||
@@ -84,6 +74,9 @@ jobs:
|
|||||||
output-dir: wheelhouse
|
output-dir: wheelhouse
|
||||||
env:
|
env:
|
||||||
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
|
CIBW_ARCHS_MACOS: x86_64 universal2 arm64
|
||||||
|
CIBW_BUILD_FRONTEND: 'build[uv]'
|
||||||
|
CIBW_FREE_THREADED_SUPPORT: 1
|
||||||
|
CIBW_PRERELEASE_PYTHONS: 1
|
||||||
|
|
||||||
- name: Run a sample build (GitHub Action, only)
|
- name: Run a sample build (GitHub Action, only)
|
||||||
uses: ./
|
uses: ./
|
||||||
@@ -127,19 +120,41 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python ./bin/run_tests.py --run-podman
|
python ./bin/run_tests.py --run-podman
|
||||||
|
|
||||||
test-emulated:
|
emulated-archs:
|
||||||
name: Test emulated cibuildwheel using qemu
|
name: Get qemu emulated architectures
|
||||||
needs: lint
|
needs: lint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 180
|
outputs:
|
||||||
|
archs: ${{ steps.archs.outputs.archs }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.x"
|
python-version: "3.x"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
run: python -m pip install ".[test]"
|
||||||
|
- name: Get qemu emulated architectures
|
||||||
|
id: archs
|
||||||
run: |
|
run: |
|
||||||
python -m pip install ".[test]"
|
OUTPUT=$(python -c "from json import dumps; from test.utils import EMULATED_ARCHS; print(dumps(EMULATED_ARCHS))")
|
||||||
|
echo "${OUTPUT}"
|
||||||
|
echo "archs=${OUTPUT}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
test-emulated:
|
||||||
|
name: Test Linux ${{ matrix.arch }} using qemu
|
||||||
|
needs: emulated-archs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 180
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
arch: ${{ fromJSON(needs.emulated-archs.outputs.archs) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: python -m pip install ".[test,uv]"
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
id: qemu
|
id: qemu
|
||||||
@@ -148,5 +163,38 @@ jobs:
|
|||||||
platforms: all
|
platforms: all
|
||||||
|
|
||||||
- name: Run the emulation tests
|
- name: Run the emulation tests
|
||||||
|
run: pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
|
||||||
|
|
||||||
|
test-pyodide:
|
||||||
|
name: Test cibuildwheel building pyodide wheels
|
||||||
|
needs: lint
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 180
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
name: Install Python 3.12
|
||||||
|
with:
|
||||||
|
python-version: '3.12'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
pytest --run-emulation test/test_emulation.py
|
python -m pip install ".[test]"
|
||||||
|
|
||||||
|
- name: Generate a sample project
|
||||||
|
run: |
|
||||||
|
python -m test.test_projects test.test_0_basic.basic_project sample_proj
|
||||||
|
|
||||||
|
- name: Run a sample build (GitHub Action)
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
package-dir: sample_proj
|
||||||
|
output-dir: wheelhouse
|
||||||
|
env:
|
||||||
|
CIBW_PLATFORM: pyodide
|
||||||
|
|
||||||
|
- name: Run tests with 'CIBW_PLATFORM' set to 'pyodide'
|
||||||
|
run: |
|
||||||
|
python ./bin/run_tests.py
|
||||||
|
env:
|
||||||
|
CIBW_PLATFORM: pyodide
|
||||||
|
|||||||
+13
-4
@@ -1,11 +1,10 @@
|
|||||||
linux:
|
linux:
|
||||||
image: python:3.8
|
image: python:3.12
|
||||||
services:
|
services:
|
||||||
- name: docker:dind
|
- name: docker:dind
|
||||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||||
command: ["dockerd-entrypoint.sh"]
|
command: ["dockerd-entrypoint.sh"]
|
||||||
variables:
|
variables:
|
||||||
DOCKER_HOST: tcp://docker:2375/
|
|
||||||
DOCKER_DRIVER: overlay2
|
DOCKER_DRIVER: overlay2
|
||||||
# See https://github.com/docker-library/docker/pull/166
|
# See https://github.com/docker-library/docker/pull/166
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
@@ -23,9 +22,19 @@ windows:
|
|||||||
variables:
|
variables:
|
||||||
PYTEST_ADDOPTS: -k "unit_test or test_0_basic" --suppress-no-test-exit-code
|
PYTEST_ADDOPTS: -k "unit_test or test_0_basic" --suppress-no-test-exit-code
|
||||||
before_script:
|
before_script:
|
||||||
- choco install python -y --version 3.8.6
|
- choco install python -y --version 3.12.4
|
||||||
script:
|
script:
|
||||||
- py -m pip install -e ".[dev]" pytest-custom-exit-code
|
- py -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||||
- py bin\run_tests.py
|
- py bin\run_tests.py
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- saas-windows-medium-amd64
|
||||||
|
|
||||||
|
macos:
|
||||||
|
image: macos-14-xcode-15
|
||||||
|
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 ./bin/run_tests.py
|
||||||
|
tags:
|
||||||
|
- saas-macos-medium-m1
|
||||||
|
|||||||
+6
-11
@@ -14,20 +14,14 @@ repos:
|
|||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.4.3
|
rev: v0.6.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--show-fixes"]
|
args: ["--fix", "--show-fixes"]
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
|
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
|
||||||
rev: v2.5.0
|
|
||||||
hooks:
|
|
||||||
- id: setup-cfg-fmt
|
|
||||||
args: [--include-version-classifiers, --min-py-version=3.8, --max-py-version=3.12]
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.10.0
|
rev: v1.11.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
name: mypy 3.8 on cibuildwheel/
|
name: mypy 3.8 on cibuildwheel/
|
||||||
@@ -46,6 +40,7 @@ repos:
|
|||||||
- types-jinja2
|
- types-jinja2
|
||||||
- types-pyyaml
|
- types-pyyaml
|
||||||
- types-requests
|
- types-requests
|
||||||
|
- uv
|
||||||
- validate-pyproject
|
- validate-pyproject
|
||||||
- id: mypy
|
- id: mypy
|
||||||
name: mypy 3.12
|
name: mypy 3.12
|
||||||
@@ -74,15 +69,15 @@ repos:
|
|||||||
files: ^docs/changelog.md$
|
files: ^docs/changelog.md$
|
||||||
|
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: v2.2.6
|
rev: v2.3.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell
|
- id: codespell
|
||||||
args: ["-L", "sur", "-w"]
|
args: ["-L", "sur,assertin", "-w"]
|
||||||
exclude: ^docs/working-examples\.md$ # Autogenerated
|
exclude: ^docs/working-examples\.md$ # Autogenerated
|
||||||
|
|
||||||
|
|
||||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||||
rev: 0.28.2
|
rev: 0.29.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-dependabot
|
- id: check-dependabot
|
||||||
- id: check-github-actions
|
- id: check-github-actions
|
||||||
|
|||||||
+2
-2
@@ -11,5 +11,5 @@ build:
|
|||||||
- asdf install uv latest
|
- asdf install uv latest
|
||||||
- asdf global uv latest
|
- asdf global uv latest
|
||||||
- uv venv
|
- uv venv
|
||||||
- uv pip install .[docs]
|
- uv pip install -e.[docs]
|
||||||
- .venv/bin/python -m mkdocs build --site-dir $READTHEDOCS_OUTPUT/html
|
- NO_COLOR=1 .venv/bin/mkdocs build --strict --site-dir $READTHEDOCS_OUTPUT/html
|
||||||
|
|||||||
+4
-1
@@ -44,6 +44,7 @@ jobs:
|
|||||||
python: 3.9
|
python: 3.9
|
||||||
services: docker
|
services: docker
|
||||||
arch: s390x
|
arch: s390x
|
||||||
|
allow_failure: True
|
||||||
env: PYTHON=python
|
env: PYTHON=python
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@@ -56,5 +57,7 @@ script: |
|
|||||||
(while true; do echo "travis_keep_alive"; sleep 300; done) &
|
(while true; do echo "travis_keep_alive"; sleep 300; done) &
|
||||||
SPINNER_PID=$!
|
SPINNER_PID=$!
|
||||||
disown
|
disown
|
||||||
$PYTHON ./bin/run_tests.py --num-processes 2
|
result=0
|
||||||
|
$PYTHON ./bin/run_tests.py --num-processes 2 || result=1
|
||||||
kill -9 ${SPINNER_PID}
|
kill -9 ${SPINNER_PID}
|
||||||
|
test ${result} -eq 0
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
This is a summary of the host Python versions and platforms covered by the different CI platforms:
|
This is a summary of the host Python versions and platforms covered by the different CI platforms:
|
||||||
|
|
||||||
| | 3.8 | 3.9 | 3.10 | 3.12 |
|
| | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 |
|
||||||
|---------|--------------------------------------------------------|-----------------------|-----------|----------------|
|
|---------|----------------------------------|-----------|-----------|---------|--------------------------------------------------|
|
||||||
| Linux | AppVeyor¹ / Azure Pipelines / GitLab¹ / GitHub Actions | CircleCI¹ / Travis CI | Cirrus CI | GitHub Actions |
|
| Linux | Azure Pipelines / GitHub Actions | Travis CI | Cirrus CI | | AppVeyor¹ / CircleCI¹ / GitHub Actions / GitLab¹ |
|
||||||
| macOS | AppVeyor¹ / Azure Pipelines | CircleCI¹ / Travis CI | Cirrus CI | GitHub Actions |
|
| macOS | Azure Pipelines | | Cirrus CI | GitLab¹ | AppVeyor¹ /CircleCI¹ / GitHub Actions |
|
||||||
| Windows | AppVeyor¹ / Azure Pipelines / GitLab¹ | Travis CI | Cirrus CI | GitHub Actions |
|
| Windows | Azure Pipelines | Travis CI | Cirrus CI | | AppVeyor¹ / GitHub Actions / GitLab¹ |
|
||||||
|
|
||||||
> ¹ Runs a reduced set of tests to reduce CI load
|
> ¹ Runs a reduced set of tests to reduce CI load
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
recursive-include cibuildwheel *.cfg
|
|
||||||
recursive-include cibuildwheel *.in
|
|
||||||
recursive-include cibuildwheel *.py
|
|
||||||
recursive-include cibuildwheel *.toml
|
|
||||||
recursive-include cibuildwheel *.txt
|
|
||||||
recursive-include cibuildwheel *.typed
|
|
||||||
@@ -22,24 +22,25 @@ Python wheels are great. Building them across **Mac, Linux, Windows**, on **mult
|
|||||||
What does it do?
|
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 |
|
| | 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 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.6 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.7 | ✅ | N/A | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.8 | ✅ | ✅ | ✅ | ✅ | N/A | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.9 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.10 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.11 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.12 | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | ✅⁴ |
|
||||||
| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ |
|
| CPython 3.13³ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅ | ✅ | ✅ | ✅ | ✅ | N/A |
|
||||||
| PyPy 3.7 v7.3 | ✅ | N/A | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | 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 |
|
| 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 |
|
| 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 |
|
| PyPy 3.10 v7.3 | ✅ | ✅ | ✅ | N/A | N/A | ✅¹ | ✅¹ | ✅¹ | N/A | N/A | N/A |
|
||||||
|
|
||||||
<sup>¹ PyPy is only supported for manylinux wheels.</sup><br>
|
<sup>¹ PyPy is only supported for manylinux wheels.</sup><br>
|
||||||
<sup>² Windows arm64 support is experimental.</sup><br>
|
<sup>² Windows arm64 support is experimental.</sup><br>
|
||||||
<sup>³ CPython 3.13 is available using the [CIBW_PRERELEASE_PYTHONS](https://cibuildwheel.pypa.io/en/stable/options/#prerelease-pythons) option.</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>⁴ Experimental, not yet supported on PyPI, but can be used directly in web deployment. Use `--platform pyodide` to build.</sup><br>
|
||||||
|
|
||||||
- Builds manylinux, musllinux, macOS 10.9+, and Windows wheels for CPython and PyPy
|
- Builds manylinux, musllinux, macOS 10.9+, and Windows wheels for CPython and PyPy
|
||||||
- Works on GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, CircleCI, GitLab CI, and Cirrus CI
|
- Works on GitHub Actions, Azure Pipelines, Travis CI, AppVeyor, CircleCI, GitLab CI, and Cirrus CI
|
||||||
@@ -60,7 +61,7 @@ Usage
|
|||||||
| Travis CI | ✅ | | ✅ | ✅ | | |
|
| Travis CI | ✅ | | ✅ | ✅ | | |
|
||||||
| AppVeyor | ✅ | ✅ | ✅ | | ✅ | ✅² |
|
| AppVeyor | ✅ | ✅ | ✅ | | ✅ | ✅² |
|
||||||
| CircleCI | ✅ | ✅ | | ✅ | ✅ | |
|
| CircleCI | ✅ | ✅ | | ✅ | ✅ | |
|
||||||
| Gitlab CI | ✅ | | ✅ | ✅¹ | | |
|
| Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | |
|
||||||
| Cirrus CI | ✅ | ✅ | ✅ | ✅ | ✅ | |
|
| Cirrus CI | ✅ | ✅ | ✅ | ✅ | ✅ | |
|
||||||
|
|
||||||
<sup>¹ [Requires emulation](https://cibuildwheel.pypa.io/en/stable/faq/#emulation), distributed separately. Other services may also support Linux ARM through emulation or third-party build hosts, but these are not tested in our CI.</sup><br>
|
<sup>¹ [Requires emulation](https://cibuildwheel.pypa.io/en/stable/faq/#emulation), distributed separately. Other services may also support Linux ARM through emulation or third-party build hosts, but these are not tested in our CI.</sup><br>
|
||||||
@@ -93,7 +94,7 @@ jobs:
|
|||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
|
|
||||||
- name: Install cibuildwheel
|
- name: Install cibuildwheel
|
||||||
run: python -m pip install cibuildwheel==2.18.0
|
run: python -m pip install cibuildwheel==2.20.0
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
run: python -m cibuildwheel --output-dir wheelhouse
|
run: python -m cibuildwheel --output-dir wheelhouse
|
||||||
@@ -160,24 +161,24 @@ Here are some repos that use cibuildwheel.
|
|||||||
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
||||||
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
||||||
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
||||||
|
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
|
||||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||||
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
|
||||||
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
||||||
|
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
||||||
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
||||||
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
|
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
|
||||||
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
|
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
|
||||||
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an in-process SQL OLAP Database Management System |
|
|
||||||
|
|
||||||
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
||||||
[pytorch-fairseq]: https://github.com/pytorch/fairseq
|
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
|
||||||
[NumPy]: https://github.com/numpy/numpy
|
[NumPy]: https://github.com/numpy/numpy
|
||||||
|
[duckdb]: https://github.com/duckdb/duckdb
|
||||||
[Tornado]: https://github.com/tornadoweb/tornado
|
[Tornado]: https://github.com/tornadoweb/tornado
|
||||||
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
|
||||||
[NCNN]: https://github.com/Tencent/ncnn
|
[NCNN]: https://github.com/Tencent/ncnn
|
||||||
|
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
||||||
[Prophet]: https://github.com/facebook/prophet
|
[Prophet]: https://github.com/facebook/prophet
|
||||||
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
|
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
|
||||||
[Kivy]: https://github.com/kivy/kivy
|
[Kivy]: https://github.com/kivy/kivy
|
||||||
[duckdb]: https://github.com/duckdb/duckdb
|
|
||||||
|
|
||||||
[appveyor icon]: docs/data/readme_icons/appveyor.svg
|
[appveyor icon]: docs/data/readme_icons/appveyor.svg
|
||||||
[github icon]: docs/data/readme_icons/github.svg
|
[github icon]: docs/data/readme_icons/github.svg
|
||||||
@@ -210,60 +211,65 @@ Changelog
|
|||||||
|
|
||||||
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
|
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
|
||||||
|
|
||||||
### v2.18.0
|
### v2.20.0
|
||||||
|
|
||||||
_12 May 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)
|
||||||
- ✨ Adds CPython 3.13 support, under the prerelease flag [CIBW_PRERELEASE_PYTHONS](https://cibuildwheel.pypa.io/en/stable/options/#prerelease-pythons). This version of cibuildwheel uses 3.13.0b1. Free-threading mode is not available yet, waiting on official binaries (planned for beta 2) and pip support.
|
- 🐛 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)
|
||||||
While CPython is in beta, the ABI can change, so your wheels might not be compatible with the final release. For this reason, we don't recommend distributing wheels until RC1, at which point 3.13 will be available in cibuildwheel without the flag. (#1816)
|
- 🛠 Undo cleaner output on pytest 8-8.2 now that 8.3 is out. (#1943)
|
||||||
- ✨ Musllinux now defaults to `musllinux_1_2`. You can set the older `manylinux_1_1` via config if needed. (#1817)
|
- 📚 Update examples to use Python 3.12 on host (cibuildwheel will require Python 3.11+ on the host machine starting in October 2024) (#1919)
|
||||||
- 🛠 No longer pre-seed setuptools/wheel in virtual environments (#1819)
|
|
||||||
- 🛠 Respect the constraints file when building with pip, matching build (#1818)
|
|
||||||
- 🛠 Use uv to compile our pinned dependencies, 10x faster and doesn't require special setup (#1778)
|
|
||||||
- 🐛 Fix an issue with the schema (#1788)
|
|
||||||
- 📚 Document the new delocate error checking macOS versions (#1766)
|
|
||||||
- 📚 Document Rust builds (#1816)
|
|
||||||
- 📚 Speed up our readthedocs builds with uv, 26 seconds -> 6 seconds to install dependencies (#1816)
|
|
||||||
|
|
||||||
|
|
||||||
### v2.17.0
|
### v2.19.2
|
||||||
|
|
||||||
_11 March 2024_
|
- 🐛 Update manylinux2014 pins to versions that support past-EoL CentOS 7 mirrors. (#1917)
|
||||||
|
- 🐛 Support `--no-isolation` with `build[uv]` build-frontend. (#1889)
|
||||||
- 🌟 Adds the ability to inherit configuration in TOML overrides. This makes certain configurations much simpler. If you're overriding an option like `before-build` or `environment`, and you just want to add an extra command or environment variable, you can just append (or prepend) to the previous config. See [the docs](https://cibuildwheel.pypa.io/en/stable/options/#inherit) for more information. (#1730)
|
- 🛠 Provide attestations for releases at <https://github.com/pypa/cibuildwheel/attestations>. (#1916)
|
||||||
- 🌟 Adds official support for native arm64 macOS GitHub runners. To use them, just specify `macos-14` as an `os` of your job in your workflow file. You can also keep `macos-13` in your build matrix to build x86_64. Check out the new [GitHub Actions example config](https://cibuildwheel.pypa.io/en/stable/setup/#github-actions).
|
- 🛠 Provide CPython 3.13.0b3. (#1913)
|
||||||
- ✨ You no longer need to specify `--platform` to run cibuildwheel locally! Instead it will detect your platform automatically. This was a safety feature, no longer necessary. (#1727)
|
- 🛠 Remove some workarounds now that pip 21.1 is available. (#1891, #1892)
|
||||||
- 🛠 Removed setuptools and wheel pinned versions. This only affects old-style projects without a `pyproject.toml`, projects with `pyproject.toml` are already getting fresh versions of their `build-system.requires` installed into an isolated environment. (#1725)
|
- 📚 Remove nosetest from our docs. (#1821)
|
||||||
- 🛠 Improve how the GitHub Action passes arguments (#1757)
|
- 📚 Document the macOS ARM workaround for 3.8 on GHA. (#1871)
|
||||||
- 🛠 Remove a system-wide install of pipx in the GitHub Action (#1745)
|
- 📚 GitLab CI + macOS is now a supported platform with an example. (#1911)
|
||||||
- 🐛 No longer will cibuildwheel override the PIP_CONSTRAINT environment variable when using the `build` frontend. Instead it will be extended. (#1675)
|
|
||||||
- 🐛 Fix a bug where building and testing both x86_86 and arm64 wheels on the same runner caused the wrong architectures in the test environment (#1750)
|
|
||||||
- 🐛 Fix a bug that prevented testing a CPython 3.8 wheel targeting macOS 11+ on x86_64 (#1768)
|
|
||||||
- 📚 Moved the docs onto the official PyPA domain - they're now available at https://cibuildwheel.pypa.io . (#1775)
|
|
||||||
- 📚 Docs and examples improvements (#1762, #1734)
|
|
||||||
|
|
||||||
|
|
||||||
### v2.16.5
|
### v2.19.1
|
||||||
|
|
||||||
_30 January 2024_
|
- 🐛 Don't require setup-python on GHA for Pyodide (#1868)
|
||||||
|
- 🐛 Specify full python path for uv (fixes issue in 0.2.10 & 0.2.11) (#1881)
|
||||||
|
- 🛠 Update for pip 24.1b2 on CPython 3.13. (#1879)
|
||||||
|
- 🛠 Fix a warning in our schema generation script. (#1866)
|
||||||
|
- 🛠 Cleaner output on pytest 8-8.2. (#1865)
|
||||||
|
|
||||||
- 🐛 Fix an incompatibility with the GitHub Action and new GitHub Runner images for Windows that bundle Powershell 7.3+ (#1741)
|
|
||||||
- 🛠 Preliminary support for new `macos-14` arm64 runners (#1743)
|
|
||||||
|
|
||||||
### v2.16.4
|
### v2.19.0
|
||||||
|
|
||||||
_28 January 2024_
|
See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more info on new features!
|
||||||
|
|
||||||
- 🛠 Update manylinux pins to upgrade from a problematic PyPy version. (#1737)
|
- 🌟 Add Pyodide platform. Set with `--platform pyodide` or `CIBW_PLATFORM: pyodide` on Linux with a host Python 3.12 to build WebAssembly wheels. Not accepted on PyPI currently, but usable directly in a website using Pyodide, for live docs, etc. (#1456, #1859)
|
||||||
|
- 🌟 Add `build[uv]` backend, which will take a pre-existing uv install (or install `cibuildwheel[uv]`) and use `uv` for all environment setup and installs on Python 3.8+. This is significantly faster in most cases. (#1856)
|
||||||
|
- ✨ Add free-threaded macOS builds and update CPython to 3.13.0b2. (#1854)
|
||||||
|
- 🐛 Issue copying a wheel to a non-existent output dir fixed. (#1851, #1862)
|
||||||
|
- 🐛 Better determinism for the test environment seeding. (#1835)
|
||||||
|
- 🛠 `VIRTUAL_ENV` variable now set. (#1842)
|
||||||
|
- 🛠 Remove a pip<21.3 workaround. (#1842)
|
||||||
|
- 🛠 Error handling was refactored to use exceptions. (#1719)
|
||||||
|
- 🛠 Hardcoded paths in tests avoided. (#1834)
|
||||||
|
- 🛠 Single Python tests made more generic. (#1835)
|
||||||
|
- 🛠 Sped up our ci by splitting up emulation tests. (#1839)
|
||||||
|
|
||||||
### v2.16.3
|
|
||||||
|
|
||||||
_26 January 2024_
|
|
||||||
|
|
||||||
- 🐛 Fix a bug when building from sdist, where relative paths to files in the package didn't work because the working directory was wrong (#1687)
|
### v2.18.1
|
||||||
- 🛠 Adds the ability to disable mounting the host filesystem in containers to `/host`, through the `disable_host_mount` suboption on [`CIBW_CONTAINER_ENGINE`](https://cibuildwheel.pypa.io/en/stable/options/#container-engine).
|
|
||||||
- 📚 A lot of docs improvements! (#1708, #1705, #1686, #1679, #1667, #1665)
|
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
|
||||||
|
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
|
||||||
|
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
|
||||||
|
- 🛠 Significant improvements and modernization to our noxfile. (#1823)
|
||||||
|
- 🛠 Use pylint's new GitHub Actions reporter instead of a custom matcher. (#1823)
|
||||||
|
- 🛠 Unpin virtualenv updates for Python 3.7+ (#1830)
|
||||||
|
- 🐛 Fix running linux tests from Windows or macOS ARM. (#1788)
|
||||||
|
- 📚 Fix our documentation build. (#1821)
|
||||||
|
|
||||||
<!-- END bin/update_readme_changelog.py -->
|
<!-- END bin/update_readme_changelog.py -->
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -24,11 +24,11 @@ branding:
|
|||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
# Set up a non-EOL, cibuildwheel & pipx supported Python version
|
# Set up the version of Python that supports pyodide
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
id: python
|
id: python
|
||||||
with:
|
with:
|
||||||
python-version: "3.8 - 3.12"
|
python-version: "3.12"
|
||||||
update-environment: false
|
update-environment: false
|
||||||
|
|
||||||
- id: cibw
|
- id: cibw
|
||||||
|
|||||||
+11
-11
@@ -1,26 +1,26 @@
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
|
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
|
||||||
APPVEYOR_JOB_NAME: "python38-x64-ubuntu"
|
APPVEYOR_JOB_NAME: "python312-x64-ubuntu"
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||||
APPVEYOR_JOB_NAME: "python38-x64-vs2015"
|
APPVEYOR_JOB_NAME: "python312-x64-vs2022"
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos
|
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
|
||||||
APPVEYOR_JOB_NAME: "python38-x64-macos"
|
APPVEYOR_JOB_NAME: "python312-x64-macos"
|
||||||
|
|
||||||
stack: python 3.8
|
stack: python 3.12
|
||||||
|
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
init:
|
init:
|
||||||
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
|
|
||||||
- ps: |
|
- ps: |
|
||||||
$BRANCH = if ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH) { $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH } else { $env:APPVEYOR_REPO_BRANCH }
|
$BRANCH = if ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH) { $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH } else { $env:APPVEYOR_REPO_BRANCH }
|
||||||
if (-not ($BRANCH -eq 'main' -or $BRANCH.ToLower().StartsWith('appveyor-'))) {
|
if (-not ($BRANCH -eq 'main' -or $BRANCH.ToLower().StartsWith('appveyor-'))) {
|
||||||
$env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
|
$env:PYTEST_ADDOPTS = '-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
|
||||||
}
|
}
|
||||||
python -m pip install -U pip
|
|
||||||
|
|
||||||
install: python -m pip install -e ".[dev]" pytest-custom-exit-code
|
install:
|
||||||
|
- python -m pip install -U pip
|
||||||
|
- python -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||||
|
|
||||||
# the '-u' flag is required so the output is in the correct order.
|
# the '-u' flag is required so the output is in the correct order.
|
||||||
# See https://github.com/pypa/cibuildwheel/pull/24 for more info.
|
# See https://github.com/pypa/cibuildwheel/pull/24 for more info.
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ jobs:
|
|||||||
python ./bin/run_tests.py
|
python ./bin/run_tests.py
|
||||||
|
|
||||||
- job: macos_38
|
- job: macos_38
|
||||||
pool: {vmImage: 'macOS-11'}
|
pool: {vmImage: 'macOS-12'}
|
||||||
steps:
|
steps:
|
||||||
- task: UsePythonVersion@0
|
- task: UsePythonVersion@0
|
||||||
inputs:
|
inputs:
|
||||||
|
|||||||
+9
-7
@@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# /// script
|
# /// script
|
||||||
# dependencies = ["click", "packaging"]
|
# dependencies = ["click", "packaging", "tomli; python_version<'3.11'"]
|
||||||
# ///
|
# ///
|
||||||
|
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import configparser
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -18,8 +17,14 @@ from pathlib import Path
|
|||||||
import click
|
import click
|
||||||
from packaging.version import InvalidVersion, Version
|
from packaging.version import InvalidVersion, Version
|
||||||
|
|
||||||
|
if sys.version_info < (3, 11):
|
||||||
|
import tomli as tomllib
|
||||||
|
else:
|
||||||
|
import tomllib
|
||||||
|
|
||||||
config = [
|
config = [
|
||||||
# file path, version find/replace format
|
# file path, version find/replace format
|
||||||
|
("pyproject.toml", 'version = "{}"'),
|
||||||
("README.md", "cibuildwheel=={}"),
|
("README.md", "cibuildwheel=={}"),
|
||||||
("cibuildwheel/__init__.py", '__version__ = "{}"'),
|
("cibuildwheel/__init__.py", '__version__ = "{}"'),
|
||||||
("docs/faq.md", "cibuildwheel=={}"),
|
("docs/faq.md", "cibuildwheel=={}"),
|
||||||
@@ -27,7 +32,6 @@ config = [
|
|||||||
("docs/setup.md", "cibuildwheel=={}"),
|
("docs/setup.md", "cibuildwheel=={}"),
|
||||||
("examples/*", "cibuildwheel=={}"),
|
("examples/*", "cibuildwheel=={}"),
|
||||||
("examples/*", "cibuildwheel@v{}"),
|
("examples/*", "cibuildwheel@v{}"),
|
||||||
("setup.cfg", "version = {}"),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
RED = "\u001b[31m"
|
RED = "\u001b[31m"
|
||||||
@@ -37,10 +41,8 @@ OFF = "\u001b[0m"
|
|||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
def bump_version() -> None:
|
def bump_version() -> None:
|
||||||
# Update if moving setup.cfg to pyproject.toml
|
with open("pyproject.toml", "rb") as f:
|
||||||
cfg = configparser.ConfigParser()
|
current_version = tomllib.load(f)["project"]["version"]
|
||||||
cfg.read("setup.cfg")
|
|
||||||
current_version = cfg["metadata"]["version"]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
commit_date_str = subprocess.run(
|
commit_date_str = subprocess.run(
|
||||||
|
|||||||
+16
-4
@@ -1,5 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# /// script
|
||||||
|
# dependencies = ["pyyaml"]
|
||||||
|
# ///
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
@@ -44,19 +48,21 @@ properties:
|
|||||||
type: string_array
|
type: string_array
|
||||||
build-frontend:
|
build-frontend:
|
||||||
default: default
|
default: default
|
||||||
description: Set the tool to use to build, either "pip" (default for now) or "build"
|
description: Set the tool to use to build, either "pip" (default for now), "build", or "build[uv]"
|
||||||
oneOf:
|
oneOf:
|
||||||
- enum: [pip, build, default]
|
- enum: [pip, build, "build[uv]", default]
|
||||||
- type: string
|
- type: string
|
||||||
pattern: '^pip; ?args:'
|
pattern: '^pip; ?args:'
|
||||||
- type: string
|
- type: string
|
||||||
pattern: '^build; ?args:'
|
pattern: '^build; ?args:'
|
||||||
|
- type: string
|
||||||
|
pattern: '^build\\[uv\\]; ?args:'
|
||||||
- type: object
|
- type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
required: [name]
|
required: [name]
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
enum: [pip, build]
|
enum: [pip, build, "build[uv]"]
|
||||||
args:
|
args:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
@@ -100,6 +106,10 @@ properties:
|
|||||||
description: Set environment variables on the host to pass-through to the container
|
description: Set environment variables on the host to pass-through to the container
|
||||||
during the build.
|
during the build.
|
||||||
type: string_array
|
type: string_array
|
||||||
|
free-threaded-support:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: The project supports free-threaded builds of Python (PEP703)
|
||||||
manylinux-aarch64-image:
|
manylinux-aarch64-image:
|
||||||
type: string
|
type: string
|
||||||
description: Specify alternative manylinux / musllinux container images
|
description: Specify alternative manylinux / musllinux container images
|
||||||
@@ -243,8 +253,8 @@ for key, value in schema["properties"].items():
|
|||||||
non_global_options = {k: {"$ref": f"#/properties/{k}"} for k in schema["properties"]}
|
non_global_options = {k: {"$ref": f"#/properties/{k}"} for k in schema["properties"]}
|
||||||
del non_global_options["build"]
|
del non_global_options["build"]
|
||||||
del non_global_options["skip"]
|
del non_global_options["skip"]
|
||||||
del non_global_options["container-engine"]
|
|
||||||
del non_global_options["test-skip"]
|
del non_global_options["test-skip"]
|
||||||
|
del non_global_options["free-threaded-support"]
|
||||||
|
|
||||||
overrides["items"]["properties"]["select"]["oneOf"] = string_array
|
overrides["items"]["properties"]["select"]["oneOf"] = string_array
|
||||||
overrides["items"]["properties"] |= non_global_options.copy()
|
overrides["items"]["properties"] |= non_global_options.copy()
|
||||||
@@ -254,6 +264,7 @@ del overrides["items"]["properties"]["archs"]
|
|||||||
not_linux = non_global_options.copy()
|
not_linux = non_global_options.copy()
|
||||||
|
|
||||||
del not_linux["environment-pass"]
|
del not_linux["environment-pass"]
|
||||||
|
del not_linux["container-engine"]
|
||||||
for key in list(not_linux):
|
for key in list(not_linux):
|
||||||
if "linux-" in key:
|
if "linux-" in key:
|
||||||
del not_linux[key]
|
del not_linux[key]
|
||||||
@@ -271,6 +282,7 @@ oses = {
|
|||||||
"linux": as_object(non_global_options),
|
"linux": as_object(non_global_options),
|
||||||
"windows": as_object(not_linux),
|
"windows": as_object(not_linux),
|
||||||
"macos": as_object(not_linux),
|
"macos": as_object(not_linux),
|
||||||
|
"pyodide": as_object(not_linux),
|
||||||
}
|
}
|
||||||
|
|
||||||
oses["linux"]["properties"]["repair-wheel-command"] = {
|
oses["linux"]["properties"]["repair-wheel-command"] = {
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# /// script
|
||||||
|
# dependencies = [
|
||||||
|
# "click",
|
||||||
|
# "pyyaml",
|
||||||
|
# "pygithub",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Convert a yaml project list into a nice table.
|
Convert a yaml project list into a nice table.
|
||||||
|
|
||||||
|
|||||||
Executable
+148
@@ -0,0 +1,148 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import difflib
|
||||||
|
import logging
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
|
import click
|
||||||
|
import packaging.specifiers
|
||||||
|
import requests
|
||||||
|
import rich
|
||||||
|
from packaging.version import InvalidVersion, Version
|
||||||
|
from rich.logging import RichHandler
|
||||||
|
from rich.syntax import Syntax
|
||||||
|
|
||||||
|
from cibuildwheel._compat import tomllib
|
||||||
|
|
||||||
|
log = logging.getLogger("cibw")
|
||||||
|
|
||||||
|
# Looking up the dir instead of using utils.resources_dir
|
||||||
|
# since we want to write to it.
|
||||||
|
DIR: Final[Path] = Path(__file__).parent.parent.resolve()
|
||||||
|
RESOURCES_DIR: Final[Path] = DIR / "cibuildwheel/resources"
|
||||||
|
|
||||||
|
NODEJS_DIST: Final[str] = "https://nodejs.org/dist/"
|
||||||
|
NODEJS_INDEX: Final[str] = f"{NODEJS_DIST}index.json"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, order=True)
|
||||||
|
class VersionTuple:
|
||||||
|
version: Version
|
||||||
|
version_string: str
|
||||||
|
|
||||||
|
|
||||||
|
def parse_nodejs_index() -> list[VersionTuple]:
|
||||||
|
versions: list[VersionTuple] = []
|
||||||
|
response = requests.get(NODEJS_INDEX)
|
||||||
|
response.raise_for_status()
|
||||||
|
versions_info = response.json()
|
||||||
|
for version_info in versions_info:
|
||||||
|
version_string = version_info.get("version", "???")
|
||||||
|
if not version_info.get("lts", False):
|
||||||
|
log.debug("Ignoring non LTS release %r", version_string)
|
||||||
|
continue
|
||||||
|
if "linux-x64" not in version_info.get("files", []):
|
||||||
|
log.warning(
|
||||||
|
"Ignoring release %r which does not include a linux-x64 binary", version_string
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
version = Version(version_string)
|
||||||
|
if version.is_devrelease:
|
||||||
|
log.info("Ignoring development release %r", str(version))
|
||||||
|
continue
|
||||||
|
if version.is_prerelease:
|
||||||
|
log.info("Ignoring pre-release %r", str(version))
|
||||||
|
continue
|
||||||
|
versions.append(VersionTuple(version, version_string))
|
||||||
|
except InvalidVersion:
|
||||||
|
log.warning("Ignoring release %r", version_string)
|
||||||
|
versions.sort(reverse=True)
|
||||||
|
return versions
|
||||||
|
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
@click.option("--force", is_flag=True)
|
||||||
|
@click.option(
|
||||||
|
"--level", default="INFO", type=click.Choice(["WARNING", "INFO", "DEBUG"], case_sensitive=False)
|
||||||
|
)
|
||||||
|
def update_nodejs(force: bool, level: str) -> None:
|
||||||
|
logging.basicConfig(
|
||||||
|
level="INFO",
|
||||||
|
format="%(message)s",
|
||||||
|
datefmt="[%X]",
|
||||||
|
handlers=[RichHandler(rich_tracebacks=True, markup=True)],
|
||||||
|
)
|
||||||
|
log.setLevel(level)
|
||||||
|
|
||||||
|
toml_file_path = RESOURCES_DIR / "nodejs.toml"
|
||||||
|
|
||||||
|
original_toml = toml_file_path.read_text()
|
||||||
|
with toml_file_path.open("rb") as f:
|
||||||
|
nodejs_data = tomllib.load(f)
|
||||||
|
|
||||||
|
nodejs_data.pop("url")
|
||||||
|
|
||||||
|
major_versions = [VersionTuple(Version(key), key) for key in nodejs_data]
|
||||||
|
major_versions.sort(reverse=True)
|
||||||
|
|
||||||
|
versions = parse_nodejs_index()
|
||||||
|
|
||||||
|
# update existing versions, 1 per LTS
|
||||||
|
for major_version in major_versions:
|
||||||
|
current = Version(nodejs_data[major_version.version_string])
|
||||||
|
specifier = packaging.specifiers.SpecifierSet(
|
||||||
|
specifiers=f"=={major_version.version.major}.*"
|
||||||
|
)
|
||||||
|
for version in versions:
|
||||||
|
if specifier.contains(version.version) and version.version > current:
|
||||||
|
nodejs_data[major_version.version_string] = version.version_string
|
||||||
|
break
|
||||||
|
|
||||||
|
# check for a new major LTS to insert
|
||||||
|
if versions and versions[0].version.major > major_versions[0].version.major:
|
||||||
|
major_versions.insert(
|
||||||
|
0,
|
||||||
|
VersionTuple(Version(str(versions[0].version.major)), f"v{versions[0].version.major}"),
|
||||||
|
)
|
||||||
|
nodejs_data[major_versions[0].version_string] = versions[0].version_string
|
||||||
|
|
||||||
|
versions_toml = "\n".join(
|
||||||
|
f'{major_version.version_string} = "{nodejs_data[major_version.version_string]}"'
|
||||||
|
for major_version in major_versions
|
||||||
|
)
|
||||||
|
result_toml = f'url = "{NODEJS_DIST}"\n{versions_toml}\n'
|
||||||
|
|
||||||
|
rich.print() # spacer
|
||||||
|
|
||||||
|
if original_toml == result_toml:
|
||||||
|
rich.print("[green]Check complete, nodejs version unchanged.")
|
||||||
|
return
|
||||||
|
|
||||||
|
rich.print("nodejs version updated.")
|
||||||
|
rich.print("Changes:")
|
||||||
|
rich.print()
|
||||||
|
|
||||||
|
toml_relpath = toml_file_path.relative_to(DIR).as_posix()
|
||||||
|
diff_lines = difflib.unified_diff(
|
||||||
|
original_toml.splitlines(keepends=True),
|
||||||
|
result_toml.splitlines(keepends=True),
|
||||||
|
fromfile=toml_relpath,
|
||||||
|
tofile=toml_relpath,
|
||||||
|
)
|
||||||
|
rich.print(Syntax("".join(diff_lines), "diff", theme="ansi_light"))
|
||||||
|
rich.print()
|
||||||
|
|
||||||
|
if force:
|
||||||
|
toml_file_path.write_text(result_toml)
|
||||||
|
rich.print("[green]TOML file updated.")
|
||||||
|
else:
|
||||||
|
rich.print("[yellow]File left unchanged. Use --force flag to update.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
update_nodejs()
|
||||||
+21
-8
@@ -58,7 +58,7 @@ AnyConfig = Union[ConfigWinCP, ConfigWinPP, ConfigMacOS]
|
|||||||
|
|
||||||
|
|
||||||
class WindowsVersions:
|
class WindowsVersions:
|
||||||
def __init__(self, arch_str: ArchStr) -> None:
|
def __init__(self, arch_str: ArchStr, free_threaded: bool) -> None:
|
||||||
response = requests.get("https://api.nuget.org/v3/index.json")
|
response = requests.get("https://api.nuget.org/v3/index.json")
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
api_info = response.json()
|
api_info = response.json()
|
||||||
@@ -72,7 +72,11 @@ class WindowsVersions:
|
|||||||
|
|
||||||
self.arch_str = arch_str
|
self.arch_str = arch_str
|
||||||
self.arch = ARCH_DICT[arch_str]
|
self.arch = ARCH_DICT[arch_str]
|
||||||
|
self.free_threaded = free_threaded
|
||||||
|
|
||||||
package = PACKAGE_DICT[arch_str]
|
package = PACKAGE_DICT[arch_str]
|
||||||
|
if free_threaded:
|
||||||
|
package = f"{package}-freethreaded"
|
||||||
|
|
||||||
response = requests.get(f"{endpoint}{package}/index.json")
|
response = requests.get(f"{endpoint}{package}/index.json")
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
@@ -92,8 +96,9 @@ class WindowsVersions:
|
|||||||
if not versions:
|
if not versions:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
flags = "t" if self.free_threaded else ""
|
||||||
version = versions[0]
|
version = versions[0]
|
||||||
identifier = f"cp{version.major}{version.minor}-{self.arch}"
|
identifier = f"cp{version.major}{version.minor}{flags}-{self.arch}"
|
||||||
return ConfigWinCP(
|
return ConfigWinCP(
|
||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
version=self.version_dict[version],
|
version=self.version_dict[version],
|
||||||
@@ -233,9 +238,12 @@ class CPythonVersions:
|
|||||||
|
|
||||||
class AllVersions:
|
class AllVersions:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.windows_32 = WindowsVersions("32")
|
self.windows_32 = WindowsVersions("32", False)
|
||||||
self.windows_64 = WindowsVersions("64")
|
self.windows_t_32 = WindowsVersions("32", True)
|
||||||
self.windows_arm64 = WindowsVersions("ARM64")
|
self.windows_64 = WindowsVersions("64", False)
|
||||||
|
self.windows_t_64 = WindowsVersions("64", True)
|
||||||
|
self.windows_arm64 = WindowsVersions("ARM64", False)
|
||||||
|
self.windows_t_arm64 = WindowsVersions("ARM64", True)
|
||||||
self.windows_pypy_64 = PyPyVersions("64")
|
self.windows_pypy_64 = PyPyVersions("64")
|
||||||
|
|
||||||
self.macos_cpython = CPythonVersions()
|
self.macos_cpython = CPythonVersions()
|
||||||
@@ -259,14 +267,19 @@ class AllVersions:
|
|||||||
config_update = self.macos_pypy.update_version_macos(spec)
|
config_update = self.macos_pypy.update_version_macos(spec)
|
||||||
elif "macosx_arm64" in identifier:
|
elif "macosx_arm64" in identifier:
|
||||||
config_update = self.macos_pypy_arm64.update_version_macos(spec)
|
config_update = self.macos_pypy_arm64.update_version_macos(spec)
|
||||||
elif "win32" in identifier:
|
elif "t-win32" in identifier and identifier.startswith("cp"):
|
||||||
if identifier.startswith("cp"):
|
config_update = self.windows_t_32.update_version_windows(spec)
|
||||||
config_update = self.windows_32.update_version_windows(spec)
|
elif "win32" in identifier and identifier.startswith("cp"):
|
||||||
|
config_update = self.windows_32.update_version_windows(spec)
|
||||||
|
elif "t-win_amd64" in identifier and identifier.startswith("cp"):
|
||||||
|
config_update = self.windows_t_64.update_version_windows(spec)
|
||||||
elif "win_amd64" in identifier:
|
elif "win_amd64" in identifier:
|
||||||
if identifier.startswith("cp"):
|
if identifier.startswith("cp"):
|
||||||
config_update = self.windows_64.update_version_windows(spec)
|
config_update = self.windows_64.update_version_windows(spec)
|
||||||
elif identifier.startswith("pp"):
|
elif identifier.startswith("pp"):
|
||||||
config_update = self.windows_pypy_64.update_version_windows(spec)
|
config_update = self.windows_pypy_64.update_version_windows(spec)
|
||||||
|
elif "t-win_arm64" in identifier and identifier.startswith("cp"):
|
||||||
|
config_update = self.windows_t_arm64.update_version_windows(spec)
|
||||||
elif "win_arm64" in identifier and identifier.startswith("cp"):
|
elif "win_arm64" in identifier and identifier.startswith("cp"):
|
||||||
config_update = self.windows_arm64.update_version_windows(spec)
|
config_update = self.windows_arm64.update_version_windows(spec)
|
||||||
|
|
||||||
|
|||||||
@@ -53,10 +53,6 @@ def git_ls_remote_versions(url) -> list[VersionTuple]:
|
|||||||
if version.is_prerelease:
|
if version.is_prerelease:
|
||||||
log.info("Ignoring pre-release %r", str(version))
|
log.info("Ignoring pre-release %r", str(version))
|
||||||
continue
|
continue
|
||||||
# Do not upgrade past 20.22.0 to keep python 3.6 compat
|
|
||||||
if version >= Version("20.22.0"):
|
|
||||||
log.info("Ignoring %r which is not compatible with python 3.6", str(version))
|
|
||||||
continue
|
|
||||||
versions.append(VersionTuple(version, version_string))
|
versions.append(VersionTuple(version, version_string))
|
||||||
except InvalidVersion:
|
except InvalidVersion:
|
||||||
log.warning("Ignoring ref %r", ref)
|
log.warning("Ignoring ref %r", ref)
|
||||||
@@ -82,15 +78,20 @@ def update_virtualenv(force: bool, level: str) -> None:
|
|||||||
|
|
||||||
original_toml = toml_file_path.read_text()
|
original_toml = toml_file_path.read_text()
|
||||||
with toml_file_path.open("rb") as f:
|
with toml_file_path.open("rb") as f:
|
||||||
loaded_file = tomllib.load(f)
|
configurations = tomllib.load(f)
|
||||||
version = str(loaded_file["version"])
|
default = configurations.pop("default")
|
||||||
|
version = str(default["version"])
|
||||||
versions = git_ls_remote_versions(GET_VIRTUALENV_GITHUB)
|
versions = git_ls_remote_versions(GET_VIRTUALENV_GITHUB)
|
||||||
if versions[0].version > Version(version):
|
if versions[0].version > Version(version):
|
||||||
version = versions[0].version_string
|
version = versions[0].version_string
|
||||||
|
|
||||||
result_toml = (
|
configurations["default"] = {
|
||||||
f'version = "{version}"\n'
|
"version": version,
|
||||||
f'url = "{GET_VIRTUALENV_URL_TEMPLATE.format(version=version)}"\n'
|
"url": GET_VIRTUALENV_URL_TEMPLATE.format(version=version),
|
||||||
|
}
|
||||||
|
result_toml = "".join(
|
||||||
|
f'{key} = {{ version = "{value["version"]}", url = "{value["url"]}" }}\n'
|
||||||
|
for key, value in configurations.items()
|
||||||
)
|
)
|
||||||
|
|
||||||
rich.print() # spacer
|
rich.print() # spacer
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
__version__ = "2.18.0"
|
__version__ = "2.20.0"
|
||||||
|
|||||||
+75
-36
@@ -1,11 +1,13 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import dataclasses
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import tarfile
|
import tarfile
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import traceback
|
||||||
import typing
|
import typing
|
||||||
from collections.abc import Iterable, Sequence, Set
|
from collections.abc import Iterable, Sequence, Set
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -15,8 +17,10 @@ from typing import Protocol
|
|||||||
import cibuildwheel
|
import cibuildwheel
|
||||||
import cibuildwheel.linux
|
import cibuildwheel.linux
|
||||||
import cibuildwheel.macos
|
import cibuildwheel.macos
|
||||||
|
import cibuildwheel.pyodide
|
||||||
import cibuildwheel.util
|
import cibuildwheel.util
|
||||||
import cibuildwheel.windows
|
import cibuildwheel.windows
|
||||||
|
from cibuildwheel import errors
|
||||||
from cibuildwheel._compat.typing import assert_never
|
from cibuildwheel._compat.typing import assert_never
|
||||||
from cibuildwheel.architecture import Architecture, allowed_architectures_check
|
from cibuildwheel.architecture import Architecture, allowed_architectures_check
|
||||||
from cibuildwheel.logger import log
|
from cibuildwheel.logger import log
|
||||||
@@ -30,10 +34,38 @@ from cibuildwheel.util import (
|
|||||||
chdir,
|
chdir,
|
||||||
detect_ci_provider,
|
detect_ci_provider,
|
||||||
fix_ansi_codes_for_github_actions,
|
fix_ansi_codes_for_github_actions,
|
||||||
|
strtobool,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class GlobalOptions:
|
||||||
|
print_traceback_on_error: bool = True # decides what happens when errors are hit.
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
global_options = GlobalOptions()
|
||||||
|
try:
|
||||||
|
main_inner(global_options)
|
||||||
|
except errors.FatalError as e:
|
||||||
|
message = e.args[0]
|
||||||
|
if log.step_active:
|
||||||
|
log.step_end_with_error(message)
|
||||||
|
else:
|
||||||
|
print(f"cibuildwheel: {message}", file=sys.stderr)
|
||||||
|
|
||||||
|
if global_options.print_traceback_on_error:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
|
||||||
|
sys.exit(e.return_code)
|
||||||
|
|
||||||
|
|
||||||
|
def main_inner(global_options: GlobalOptions) -> None:
|
||||||
|
"""
|
||||||
|
`main_inner` is the same as `main`, but it raises FatalError exceptions
|
||||||
|
rather than exiting directly.
|
||||||
|
"""
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Build wheels for all the platforms.",
|
description="Build wheels for all the platforms.",
|
||||||
epilog="""
|
epilog="""
|
||||||
@@ -45,7 +77,7 @@ def main() -> None:
|
|||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--platform",
|
"--platform",
|
||||||
choices=["auto", "linux", "macos", "windows"],
|
choices=["auto", "linux", "macos", "windows", "pyodide"],
|
||||||
default=None,
|
default=None,
|
||||||
help="""
|
help="""
|
||||||
Platform to build for. Use this option to override the
|
Platform to build for. Use this option to override the
|
||||||
@@ -131,8 +163,17 @@ def main() -> None:
|
|||||||
help="Enable pre-release Python versions if available.",
|
help="Enable pre-release Python versions if available.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--debug-traceback",
|
||||||
|
action="store_true",
|
||||||
|
default=strtobool(os.environ.get("CIBW_DEBUG_TRACEBACK", "0")),
|
||||||
|
help="Print a full traceback for all errors",
|
||||||
|
)
|
||||||
|
|
||||||
args = CommandLineArguments(**vars(parser.parse_args()))
|
args = CommandLineArguments(**vars(parser.parse_args()))
|
||||||
|
|
||||||
|
global_options.print_traceback_on_error = args.debug_traceback
|
||||||
|
|
||||||
args.package_dir = args.package_dir.resolve()
|
args.package_dir = args.package_dir.resolve()
|
||||||
|
|
||||||
# This are always relative to the base directory, even in SDist builds
|
# This are always relative to the base directory, even in SDist builds
|
||||||
@@ -176,11 +217,10 @@ def _compute_platform_only(only: str) -> PlatformName:
|
|||||||
return "macos"
|
return "macos"
|
||||||
if "win_" in only or "win32" in only:
|
if "win_" in only or "win32" in only:
|
||||||
return "windows"
|
return "windows"
|
||||||
print(
|
if "pyodide_" in only:
|
||||||
f"Invalid --only='{only}', must be a build selector with a known platform",
|
return "pyodide"
|
||||||
file=sys.stderr,
|
msg = f"Invalid --only='{only}', must be a build selector with a known platform"
|
||||||
)
|
raise errors.ConfigurationError(msg)
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
|
|
||||||
def _compute_platform_auto() -> PlatformName:
|
def _compute_platform_auto() -> PlatformName:
|
||||||
@@ -191,34 +231,27 @@ def _compute_platform_auto() -> PlatformName:
|
|||||||
elif sys.platform == "win32":
|
elif sys.platform == "win32":
|
||||||
return "windows"
|
return "windows"
|
||||||
else:
|
else:
|
||||||
print(
|
msg = (
|
||||||
'cibuildwheel: Unable to detect platform from "sys.platform". cibuildwheel doesn\'t '
|
'cibuildwheel: Unable to detect platform from "sys.platform". cibuildwheel doesn\'t '
|
||||||
"support building wheels for this platform. You might be able to build for a different "
|
"support building wheels for this platform. You might be able to build for a different "
|
||||||
"platform using the --platform argument. Check --help output for more information.",
|
"platform using the --platform argument. Check --help output for more information."
|
||||||
file=sys.stderr,
|
|
||||||
)
|
)
|
||||||
sys.exit(2)
|
raise errors.ConfigurationError(msg)
|
||||||
|
|
||||||
|
|
||||||
def _compute_platform(args: CommandLineArguments) -> PlatformName:
|
def _compute_platform(args: CommandLineArguments) -> PlatformName:
|
||||||
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "auto")
|
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "") or "auto"
|
||||||
|
|
||||||
if args.only and args.platform is not None:
|
if args.only and args.platform is not None:
|
||||||
print(
|
msg = "--platform cannot be specified with --only, it is computed from --only"
|
||||||
"--platform cannot be specified with --only, it is computed from --only",
|
raise errors.ConfigurationError(msg)
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(2)
|
|
||||||
if args.only and args.archs is not None:
|
if args.only and args.archs is not None:
|
||||||
print(
|
msg = "--arch cannot be specified with --only, it is computed from --only"
|
||||||
"--arch cannot be specified with --only, it is computed from --only",
|
raise errors.ConfigurationError(msg)
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
if platform_option_value not in PLATFORMS | {"auto"}:
|
if platform_option_value not in PLATFORMS | {"auto"}:
|
||||||
print(f"cibuildwheel: Unsupported platform: {platform_option_value}", file=sys.stderr)
|
msg = f"Unsupported platform: {platform_option_value}"
|
||||||
sys.exit(2)
|
raise errors.ConfigurationError(msg)
|
||||||
|
|
||||||
if args.only:
|
if args.only:
|
||||||
return _compute_platform_only(args.only)
|
return _compute_platform_only(args.only)
|
||||||
@@ -246,11 +279,18 @@ def get_platform_module(platform: PlatformName) -> PlatformModule:
|
|||||||
return cibuildwheel.windows
|
return cibuildwheel.windows
|
||||||
if platform == "macos":
|
if platform == "macos":
|
||||||
return cibuildwheel.macos
|
return cibuildwheel.macos
|
||||||
|
if platform == "pyodide":
|
||||||
|
return cibuildwheel.pyodide
|
||||||
assert_never(platform)
|
assert_never(platform)
|
||||||
|
|
||||||
|
|
||||||
def build_in_directory(args: CommandLineArguments) -> None:
|
def build_in_directory(args: CommandLineArguments) -> None:
|
||||||
platform: PlatformName = _compute_platform(args)
|
platform: PlatformName = _compute_platform(args)
|
||||||
|
if platform == "pyodide" and sys.platform == "win32":
|
||||||
|
msg = "cibuildwheel: Building for pyodide is not supported on Windows"
|
||||||
|
print(msg, file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
options = compute_options(platform=platform, command_line_arguments=args, env=os.environ)
|
options = compute_options(platform=platform, command_line_arguments=args, env=os.environ)
|
||||||
|
|
||||||
package_dir = options.globals.package_dir
|
package_dir = options.globals.package_dir
|
||||||
@@ -258,9 +298,8 @@ def build_in_directory(args: CommandLineArguments) -> None:
|
|||||||
|
|
||||||
if not any(package_dir.joinpath(name).exists() for name in package_files):
|
if not any(package_dir.joinpath(name).exists() for name in package_files):
|
||||||
names = ", ".join(sorted(package_files, reverse=True))
|
names = ", ".join(sorted(package_files, reverse=True))
|
||||||
msg = f"cibuildwheel: Could not find any of {{{names}}} at root of package"
|
msg = f"Could not find any of {{{names}}} at root of package"
|
||||||
print(msg, file=sys.stderr)
|
raise errors.ConfigurationError(msg)
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
platform_module = get_platform_module(platform)
|
platform_module = get_platform_module(platform)
|
||||||
identifiers = get_build_identifiers(
|
identifiers = get_build_identifiers(
|
||||||
@@ -280,7 +319,7 @@ def build_in_directory(args: CommandLineArguments) -> None:
|
|||||||
# Python is buffering by default when running on the CI platforms, giving
|
# Python is buffering by default when running on the CI platforms, giving
|
||||||
# problems interleaving subprocess call output with unflushed calls to
|
# problems interleaving subprocess call output with unflushed calls to
|
||||||
# 'print'
|
# 'print'
|
||||||
sys.stdout = Unbuffered(sys.stdout) # type: ignore[assignment]
|
sys.stdout = Unbuffered(sys.stdout)
|
||||||
|
|
||||||
# create the cache dir before it gets printed & builds performed
|
# create the cache dir before it gets printed & builds performed
|
||||||
CIBW_CACHE_PATH.mkdir(parents=True, exist_ok=True)
|
CIBW_CACHE_PATH.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -291,16 +330,14 @@ def build_in_directory(args: CommandLineArguments) -> None:
|
|||||||
options.check_for_invalid_configuration(identifiers)
|
options.check_for_invalid_configuration(identifiers)
|
||||||
allowed_architectures_check(platform, options.globals.architectures)
|
allowed_architectures_check(platform, options.globals.architectures)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
print("cibuildwheel:", *err.args, file=sys.stderr)
|
raise errors.DeprecationError(*err.args) from err
|
||||||
sys.exit(4)
|
|
||||||
|
|
||||||
if not identifiers:
|
if not identifiers:
|
||||||
print(
|
message = f"No build identifiers selected: {options.globals.build_selector}"
|
||||||
f"cibuildwheel: No build identifiers selected: {options.globals.build_selector}",
|
if options.globals.allow_empty:
|
||||||
file=sys.stderr,
|
print(f"cibuildwheel: {message}", file=sys.stderr)
|
||||||
)
|
else:
|
||||||
if not args.allow_empty:
|
raise errors.NothingToDoError(message)
|
||||||
sys.exit(3)
|
|
||||||
|
|
||||||
output_dir = options.globals.output_dir
|
output_dir = options.globals.output_dir
|
||||||
|
|
||||||
@@ -355,7 +392,9 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
|
|||||||
|
|
||||||
|
|
||||||
def get_build_identifiers(
|
def get_build_identifiers(
|
||||||
platform_module: PlatformModule, build_selector: BuildSelector, architectures: Set[Architecture]
|
platform_module: PlatformModule,
|
||||||
|
build_selector: BuildSelector,
|
||||||
|
architectures: Set[Architecture],
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
|
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
|
||||||
return [config.identifier for config in python_configurations]
|
return [config.identifier for config in python_configurations]
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ PRETTY_NAMES: Final[dict[PlatformName, str]] = {
|
|||||||
"linux": "Linux",
|
"linux": "Linux",
|
||||||
"macos": "macOS",
|
"macos": "macOS",
|
||||||
"windows": "Windows",
|
"windows": "Windows",
|
||||||
|
"pyodide": "Pyodide",
|
||||||
}
|
}
|
||||||
|
|
||||||
ARCH_SYNONYMS: Final[list[dict[PlatformName, str | None]]] = [
|
ARCH_SYNONYMS: Final[list[dict[PlatformName, str | None]]] = [
|
||||||
@@ -46,6 +47,9 @@ class Architecture(Enum):
|
|||||||
AMD64 = "AMD64"
|
AMD64 = "AMD64"
|
||||||
ARM64 = "ARM64"
|
ARM64 = "ARM64"
|
||||||
|
|
||||||
|
# WebAssembly
|
||||||
|
wasm32 = "wasm32"
|
||||||
|
|
||||||
# Allow this to be sorted
|
# Allow this to be sorted
|
||||||
def __lt__(self, other: Architecture) -> bool:
|
def __lt__(self, other: Architecture) -> bool:
|
||||||
return self.value < other.value
|
return self.value < other.value
|
||||||
@@ -72,8 +76,9 @@ class Architecture(Enum):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def auto_archs(platform: PlatformName) -> set[Architecture]:
|
def native_arch(platform: PlatformName) -> Architecture | None:
|
||||||
native_machine = platform_module.machine()
|
if platform == "pyodide":
|
||||||
|
return Architecture.wasm32
|
||||||
|
|
||||||
# Cross-platform support. Used for --print-build-identifiers or docker builds.
|
# Cross-platform support. Used for --print-build-identifiers or docker builds.
|
||||||
host_platform: PlatformName = (
|
host_platform: PlatformName = (
|
||||||
@@ -82,6 +87,7 @@ class Architecture(Enum):
|
|||||||
else ("macos" if sys.platform.startswith("darwin") else "linux")
|
else ("macos" if sys.platform.startswith("darwin") else "linux")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
native_machine = platform_module.machine()
|
||||||
native_architecture = Architecture(native_machine)
|
native_architecture = Architecture(native_machine)
|
||||||
|
|
||||||
# we might need to rename the native arch to the machine we're running
|
# we might need to rename the native arch to the machine we're running
|
||||||
@@ -93,11 +99,18 @@ class Architecture(Enum):
|
|||||||
|
|
||||||
if synonym is None:
|
if synonym is None:
|
||||||
# can't build anything on this platform
|
# can't build anything on this platform
|
||||||
return set()
|
return None
|
||||||
|
|
||||||
native_architecture = Architecture(synonym)
|
native_architecture = Architecture(synonym)
|
||||||
|
|
||||||
result = {native_architecture}
|
return native_architecture
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def auto_archs(platform: PlatformName) -> set[Architecture]:
|
||||||
|
native_arch = Architecture.native_arch(platform)
|
||||||
|
if native_arch is None:
|
||||||
|
return set() # can't build anything on this platform
|
||||||
|
result = {native_arch}
|
||||||
|
|
||||||
if platform == "linux" and Architecture.x86_64 in result:
|
if platform == "linux" and Architecture.x86_64 in result:
|
||||||
# x86_64 machines can run i686 containers
|
# x86_64 machines can run i686 containers
|
||||||
@@ -120,6 +133,7 @@ class Architecture(Enum):
|
|||||||
},
|
},
|
||||||
"macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2},
|
"macos": {Architecture.x86_64, Architecture.arm64, Architecture.universal2},
|
||||||
"windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64},
|
"windows": {Architecture.x86, Architecture.AMD64, Architecture.ARM64},
|
||||||
|
"pyodide": {Architecture.wasm32},
|
||||||
}
|
}
|
||||||
return all_archs_map[platform]
|
return all_archs_map[platform]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
Errors that can cause the build to fail. Each subclass of FatalError has
|
||||||
|
a different return code, by defining them all here, we can ensure that they're
|
||||||
|
semantically clear and unique.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
|
||||||
|
class FatalError(BaseException):
|
||||||
|
"""
|
||||||
|
Raising an error of this type will cause the message to be printed to
|
||||||
|
stderr and the process to be terminated. Within cibuildwheel, raising this
|
||||||
|
exception produces a better error message, and optional traceback.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return_code: int = 1
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationError(FatalError):
|
||||||
|
return_code = 2
|
||||||
|
|
||||||
|
|
||||||
|
class NothingToDoError(FatalError):
|
||||||
|
return_code = 3
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecationError(FatalError):
|
||||||
|
return_code = 4
|
||||||
|
|
||||||
|
|
||||||
|
class NonPlatformWheelError(FatalError):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
message = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
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 expected a platform wheel, check your project configuration, or run
|
||||||
|
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
super().__init__(message)
|
||||||
|
self.return_code = 5
|
||||||
|
|
||||||
|
|
||||||
|
class AlreadyBuiltWheelError(FatalError):
|
||||||
|
def __init__(self, wheel_name: str) -> None:
|
||||||
|
message = textwrap.dedent(
|
||||||
|
f"""
|
||||||
|
Build failed because a wheel named {wheel_name} was already generated in the current run.
|
||||||
|
|
||||||
|
If you expected another wheel to be generated, check your project configuration, or run
|
||||||
|
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
super().__init__(message)
|
||||||
|
self.return_code = 6
|
||||||
+76
-63
@@ -8,17 +8,18 @@ from dataclasses import dataclass
|
|||||||
from pathlib import Path, PurePath, PurePosixPath
|
from pathlib import Path, PurePath, PurePosixPath
|
||||||
from typing import OrderedDict, Tuple
|
from typing import OrderedDict, Tuple
|
||||||
|
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from . import errors
|
||||||
from ._compat.typing import assert_never
|
from ._compat.typing import assert_never
|
||||||
from .architecture import Architecture
|
from .architecture import Architecture
|
||||||
from .logger import log
|
from .logger import log
|
||||||
from .oci_container import OCIContainer
|
from .oci_container import OCIContainer, OCIContainerEngineConfig
|
||||||
from .options import Options
|
from .options import BuildOptions, Options
|
||||||
from .typing import PathOrStr
|
from .typing import PathOrStr
|
||||||
from .util import (
|
from .util import (
|
||||||
AlreadyBuiltWheelError,
|
|
||||||
BuildFrontendConfig,
|
BuildFrontendConfig,
|
||||||
BuildSelector,
|
BuildSelector,
|
||||||
NonPlatformWheelError,
|
|
||||||
find_compatible_wheel,
|
find_compatible_wheel,
|
||||||
get_build_verbosity_extra_flags,
|
get_build_verbosity_extra_flags,
|
||||||
prepare_command,
|
prepare_command,
|
||||||
@@ -44,6 +45,7 @@ class PythonConfiguration:
|
|||||||
class BuildStep:
|
class BuildStep:
|
||||||
platform_configs: list[PythonConfiguration]
|
platform_configs: list[PythonConfiguration]
|
||||||
platform_tag: str
|
platform_tag: str
|
||||||
|
container_engine: OCIContainerEngineConfig
|
||||||
container_image: str
|
container_image: str
|
||||||
|
|
||||||
|
|
||||||
@@ -65,8 +67,9 @@ def get_python_configurations(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def container_image_for_python_configuration(config: PythonConfiguration, options: Options) -> str:
|
def container_image_for_python_configuration(
|
||||||
build_options = options.build_options(config.identifier)
|
config: PythonConfiguration, build_options: BuildOptions
|
||||||
|
) -> str:
|
||||||
# e.g
|
# e.g
|
||||||
# identifier is 'cp310-manylinux_x86_64'
|
# identifier is 'cp310-manylinux_x86_64'
|
||||||
# platform_tag is 'manylinux_x86_64'
|
# platform_tag is 'manylinux_x86_64'
|
||||||
@@ -91,15 +94,18 @@ def get_build_steps(
|
|||||||
Groups PythonConfigurations into BuildSteps. Each BuildStep represents a
|
Groups PythonConfigurations into BuildSteps. Each BuildStep represents a
|
||||||
separate container instance.
|
separate container instance.
|
||||||
"""
|
"""
|
||||||
steps = OrderedDict[Tuple[str, str, str], BuildStep]()
|
steps = OrderedDict[Tuple[str, str, str, OCIContainerEngineConfig], BuildStep]()
|
||||||
|
|
||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
_, platform_tag = config.identifier.split("-", 1)
|
_, platform_tag = config.identifier.split("-", 1)
|
||||||
|
|
||||||
before_all = options.build_options(config.identifier).before_all
|
build_options = options.build_options(config.identifier)
|
||||||
container_image = container_image_for_python_configuration(config, options)
|
|
||||||
|
|
||||||
step_key = (platform_tag, container_image, before_all)
|
before_all = build_options.before_all
|
||||||
|
container_image = container_image_for_python_configuration(config, build_options)
|
||||||
|
container_engine = build_options.container_engine
|
||||||
|
|
||||||
|
step_key = (platform_tag, container_image, before_all, container_engine)
|
||||||
|
|
||||||
if step_key in steps:
|
if step_key in steps:
|
||||||
steps[step_key].platform_configs.append(config)
|
steps[step_key].platform_configs.append(config)
|
||||||
@@ -107,6 +113,7 @@ def get_build_steps(
|
|||||||
steps[step_key] = BuildStep(
|
steps[step_key] = BuildStep(
|
||||||
platform_configs=[config],
|
platform_configs=[config],
|
||||||
platform_tag=platform_tag,
|
platform_tag=platform_tag,
|
||||||
|
container_engine=container_engine,
|
||||||
container_image=container_image,
|
container_image=container_image,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -139,11 +146,7 @@ def check_all_python_exist(
|
|||||||
exist = False
|
exist = False
|
||||||
if not exist:
|
if not exist:
|
||||||
message = "\n".join(messages)
|
message = "\n".join(messages)
|
||||||
print(
|
raise errors.FatalError(message)
|
||||||
f"cibuildwheel:\n{message}",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def build_in_container(
|
def build_in_container(
|
||||||
@@ -188,6 +191,8 @@ def build_in_container(
|
|||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
build_options = options.build_options(config.identifier)
|
build_options = options.build_options(config.identifier)
|
||||||
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
|
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
|
||||||
|
use_uv = build_frontend.name == "build[uv]" and Version(config.version) >= Version("3.8")
|
||||||
|
pip = ["uv", "pip"] if use_uv else ["pip"]
|
||||||
|
|
||||||
dependency_constraint_flags: list[PathOrStr] = []
|
dependency_constraint_flags: list[PathOrStr] = []
|
||||||
|
|
||||||
@@ -215,19 +220,19 @@ def build_in_container(
|
|||||||
# check config python is still on PATH
|
# check config python is still on PATH
|
||||||
which_python = container.call(["which", "python"], env=env, capture_output=True).strip()
|
which_python = container.call(["which", "python"], env=env, capture_output=True).strip()
|
||||||
if PurePosixPath(which_python) != python_bin / "python":
|
if PurePosixPath(which_python) != python_bin / "python":
|
||||||
print(
|
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."
|
||||||
"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)
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
which_pip = container.call(["which", "pip"], env=env, capture_output=True).strip()
|
if use_uv:
|
||||||
if PurePosixPath(which_pip) != python_bin / "pip":
|
which_uv = container.call(["which", "uv"], env=env, capture_output=True).strip()
|
||||||
print(
|
if not which_uv:
|
||||||
"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.",
|
msg = "uv not found on PATH. You must use a supported manylinux or musllinux environment with uv."
|
||||||
file=sys.stderr,
|
raise errors.FatalError(msg)
|
||||||
)
|
else:
|
||||||
sys.exit(1)
|
which_pip = container.call(["which", "pip"], env=env, capture_output=True).strip()
|
||||||
|
if PurePosixPath(which_pip) != python_bin / "pip":
|
||||||
|
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)
|
||||||
|
|
||||||
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
if compatible_wheel:
|
if compatible_wheel:
|
||||||
@@ -271,10 +276,12 @@ def build_in_container(
|
|||||||
],
|
],
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
elif build_frontend.name == "build":
|
elif build_frontend.name == "build" or build_frontend.name == "build[uv]":
|
||||||
if not 0 <= build_options.build_verbosity < 2:
|
if not 0 <= build_options.build_verbosity < 2:
|
||||||
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
||||||
log.warning(msg)
|
log.warning(msg)
|
||||||
|
if use_uv and "--no-isolation" not in extra_flags and "-n" not in extra_flags:
|
||||||
|
extra_flags += ["--installer=uv"]
|
||||||
container.call(
|
container.call(
|
||||||
[
|
[
|
||||||
"python",
|
"python",
|
||||||
@@ -297,7 +304,7 @@ def build_in_container(
|
|||||||
container.call(["mkdir", "-p", repaired_wheel_dir])
|
container.call(["mkdir", "-p", repaired_wheel_dir])
|
||||||
|
|
||||||
if built_wheel.name.endswith("none-any.whl"):
|
if built_wheel.name.endswith("none-any.whl"):
|
||||||
raise NonPlatformWheelError()
|
raise errors.NonPlatformWheelError()
|
||||||
|
|
||||||
if build_options.repair_command:
|
if build_options.repair_command:
|
||||||
log.step("Repairing wheel...")
|
log.step("Repairing wheel...")
|
||||||
@@ -312,24 +319,36 @@ def build_in_container(
|
|||||||
|
|
||||||
for repaired_wheel in repaired_wheels:
|
for repaired_wheel in repaired_wheels:
|
||||||
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
||||||
raise AlreadyBuiltWheelError(repaired_wheel.name)
|
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
|
||||||
|
|
||||||
if build_options.test_command and build_options.test_selector(config.identifier):
|
if build_options.test_command and build_options.test_selector(config.identifier):
|
||||||
log.step("Testing wheel...")
|
log.step("Testing wheel...")
|
||||||
|
|
||||||
# set up a virtual environment to install and test from, to make sure
|
# set up a virtual environment to install and test from, to make sure
|
||||||
# there are no dependencies that were pulled in at build time.
|
# there are no dependencies that were pulled in at build time.
|
||||||
container.call(["pip", "install", "virtualenv", *dependency_constraint_flags], env=env)
|
if not use_uv:
|
||||||
|
container.call(
|
||||||
|
["pip", "install", "virtualenv", *dependency_constraint_flags], env=env
|
||||||
|
)
|
||||||
|
|
||||||
testing_temp_dir = PurePosixPath(
|
testing_temp_dir = PurePosixPath(
|
||||||
container.call(["mktemp", "-d"], capture_output=True).strip()
|
container.call(["mktemp", "-d"], capture_output=True).strip()
|
||||||
)
|
)
|
||||||
venv_dir = testing_temp_dir / "venv"
|
venv_dir = testing_temp_dir / "venv"
|
||||||
|
|
||||||
container.call(["python", "-m", "virtualenv", "--no-download", venv_dir], env=env)
|
if use_uv:
|
||||||
|
container.call(["uv", "venv", venv_dir], env=env)
|
||||||
|
else:
|
||||||
|
# Use embedded dependencies from virtualenv to ensure determinism
|
||||||
|
venv_args = ["--no-periodic-update", "--pip=embed"]
|
||||||
|
# In Python<3.12, setuptools & wheel are installed as well
|
||||||
|
if Version(config.version) < Version("3.12"):
|
||||||
|
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
|
||||||
|
container.call(["python", "-m", "virtualenv", *venv_args, venv_dir], env=env)
|
||||||
|
|
||||||
virtualenv_env = env.copy()
|
virtualenv_env = env.copy()
|
||||||
virtualenv_env["PATH"] = f"{venv_dir / 'bin'}:{virtualenv_env['PATH']}"
|
virtualenv_env["PATH"] = f"{venv_dir / 'bin'}:{virtualenv_env['PATH']}"
|
||||||
|
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
||||||
|
|
||||||
if build_options.before_test:
|
if build_options.before_test:
|
||||||
before_test_prepared = prepare_command(
|
before_test_prepared = prepare_command(
|
||||||
@@ -347,13 +366,13 @@ def build_in_container(
|
|||||||
# Let's just pick the first one.
|
# Let's just pick the first one.
|
||||||
wheel_to_test = repaired_wheels[0]
|
wheel_to_test = repaired_wheels[0]
|
||||||
container.call(
|
container.call(
|
||||||
["pip", "install", str(wheel_to_test) + build_options.test_extras],
|
[*pip, "install", str(wheel_to_test) + build_options.test_extras],
|
||||||
env=virtualenv_env,
|
env=virtualenv_env,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Install any requirements to run the tests
|
# Install any requirements to run the tests
|
||||||
if build_options.test_requires:
|
if build_options.test_requires:
|
||||||
container.call(["pip", "install", *build_options.test_requires], env=virtualenv_env)
|
container.call([*pip, "install", *build_options.test_requires], env=virtualenv_env)
|
||||||
|
|
||||||
# Run the tests from a different directory
|
# Run the tests from a different directory
|
||||||
test_command_prepared = prepare_command(
|
test_command_prepared = prepare_command(
|
||||||
@@ -388,29 +407,6 @@ def build_in_container(
|
|||||||
|
|
||||||
|
|
||||||
def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
||||||
try:
|
|
||||||
# check the container engine is installed
|
|
||||||
subprocess.run(
|
|
||||||
[options.globals.container_engine.name, "--version"],
|
|
||||||
check=True,
|
|
||||||
stdout=subprocess.DEVNULL,
|
|
||||||
)
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
print(
|
|
||||||
unwrap(
|
|
||||||
f"""
|
|
||||||
cibuildwheel: {options.globals.container_engine} not found. An
|
|
||||||
OCI exe like Docker or Podman is required to run Linux builds.
|
|
||||||
If you're building on Travis CI, add `services: [docker]` to
|
|
||||||
your .travis.yml. If you're building on Circle CI in Linux,
|
|
||||||
add a `setup_remote_docker` step to your .circleci/config.yml.
|
|
||||||
If you're building on Cirrus CI, use `docker_builder` task.
|
|
||||||
"""
|
|
||||||
),
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
python_configurations = get_python_configurations(
|
python_configurations = get_python_configurations(
|
||||||
options.globals.build_selector, options.globals.architectures
|
options.globals.build_selector, options.globals.architectures
|
||||||
)
|
)
|
||||||
@@ -425,6 +421,26 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
|||||||
container_package_dir = container_project_path / abs_package_dir.relative_to(cwd)
|
container_package_dir = container_project_path / abs_package_dir.relative_to(cwd)
|
||||||
|
|
||||||
for build_step in get_build_steps(options, python_configurations):
|
for build_step in get_build_steps(options, python_configurations):
|
||||||
|
try:
|
||||||
|
# check the container engine is installed
|
||||||
|
subprocess.run(
|
||||||
|
[build_step.container_engine.name, "--version"],
|
||||||
|
check=True,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as error:
|
||||||
|
msg = unwrap(
|
||||||
|
f"""
|
||||||
|
cibuildwheel: {build_step.container_engine.name} not found. An
|
||||||
|
OCI exe like Docker or Podman is required to run Linux builds.
|
||||||
|
If you're building on Travis CI, add `services: [docker]` to
|
||||||
|
your .travis.yml. If you're building on Circle CI in Linux,
|
||||||
|
add a `setup_remote_docker` step to your .circleci/config.yml.
|
||||||
|
If you're building on Cirrus CI, use `docker_builder` task.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
raise errors.ConfigurationError(msg) from error
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ids_to_build = [x.identifier for x in build_step.platform_configs]
|
ids_to_build = [x.identifier for x in build_step.platform_configs]
|
||||||
log.step(f"Starting container image {build_step.container_image}...")
|
log.step(f"Starting container image {build_step.container_image}...")
|
||||||
@@ -435,7 +451,7 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
|||||||
image=build_step.container_image,
|
image=build_step.container_image,
|
||||||
enforce_32_bit=build_step.platform_tag.endswith("i686"),
|
enforce_32_bit=build_step.platform_tag.endswith("i686"),
|
||||||
cwd=container_project_path,
|
cwd=container_project_path,
|
||||||
engine=options.globals.container_engine,
|
engine=build_step.container_engine,
|
||||||
) as container:
|
) as container:
|
||||||
build_in_container(
|
build_in_container(
|
||||||
options=options,
|
options=options,
|
||||||
@@ -446,11 +462,9 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
|||||||
)
|
)
|
||||||
|
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
log.step_end_with_error(
|
|
||||||
f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}"
|
|
||||||
)
|
|
||||||
troubleshoot(options, error)
|
troubleshoot(options, error)
|
||||||
sys.exit(1)
|
msg = f"Command {error.cmd} failed with code {error.returncode}. {error.stdout or ''}"
|
||||||
|
raise errors.FatalError(msg) from error
|
||||||
|
|
||||||
|
|
||||||
def _matches_prepared_command(error_cmd: Sequence[str], command_template: str) -> bool:
|
def _matches_prepared_command(error_cmd: Sequence[str], command_template: str) -> bool:
|
||||||
@@ -469,7 +483,6 @@ def troubleshoot(options: Options, error: Exception) -> None:
|
|||||||
) # TODO allow matching of overrides too?
|
) # TODO allow matching of overrides too?
|
||||||
):
|
):
|
||||||
# the wheel build step or the repair step failed
|
# the wheel build step or the repair step failed
|
||||||
print("Checking for common errors...")
|
|
||||||
so_files = list(options.globals.package_dir.glob("**/*.so"))
|
so_files = list(options.globals.package_dir.glob("**/*.so"))
|
||||||
|
|
||||||
if so_files:
|
if so_files:
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ PLATFORM_IDENTIFIER_DESCRIPTIONS: Final[dict[str, str]] = {
|
|||||||
"macosx_x86_64": "macOS x86_64",
|
"macosx_x86_64": "macOS x86_64",
|
||||||
"macosx_universal2": "macOS Universal 2 - x86_64 and arm64",
|
"macosx_universal2": "macOS Universal 2 - x86_64 and arm64",
|
||||||
"macosx_arm64": "macOS arm64 - Apple Silicon",
|
"macosx_arm64": "macOS arm64 - Apple Silicon",
|
||||||
|
"pyodide_wasm32": "Pyodide",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,6 +152,10 @@ class Logger:
|
|||||||
c = self.colors
|
c = self.colors
|
||||||
print(f"{c.bright_red}Error{c.end}: {error}\n", file=sys.stderr)
|
print(f"{c.bright_red}Error{c.end}: {error}\n", file=sys.stderr)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def step_active(self) -> bool:
|
||||||
|
return self.step_start_time is not None
|
||||||
|
|
||||||
def _start_fold_group(self, name: str) -> None:
|
def _start_fold_group(self, name: str) -> None:
|
||||||
self._end_fold_group()
|
self._end_fold_group()
|
||||||
self.active_fold_group_name = name
|
self.active_fold_group_name = name
|
||||||
|
|||||||
+176
-74
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import contextlib
|
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
@@ -15,7 +14,9 @@ from pathlib import Path
|
|||||||
from typing import Literal, Tuple
|
from typing import Literal, Tuple
|
||||||
|
|
||||||
from filelock import FileLock
|
from filelock import FileLock
|
||||||
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from . import errors
|
||||||
from ._compat.typing import assert_never
|
from ._compat.typing import assert_never
|
||||||
from .architecture import Architecture
|
from .architecture import Architecture
|
||||||
from .environment import ParsedEnvironment
|
from .environment import ParsedEnvironment
|
||||||
@@ -24,18 +25,20 @@ from .options import Options
|
|||||||
from .typing import PathOrStr
|
from .typing import PathOrStr
|
||||||
from .util import (
|
from .util import (
|
||||||
CIBW_CACHE_PATH,
|
CIBW_CACHE_PATH,
|
||||||
AlreadyBuiltWheelError,
|
|
||||||
BuildFrontendConfig,
|
BuildFrontendConfig,
|
||||||
BuildFrontendName,
|
BuildFrontendName,
|
||||||
BuildSelector,
|
BuildSelector,
|
||||||
NonPlatformWheelError,
|
|
||||||
call,
|
call,
|
||||||
|
combine_constraints,
|
||||||
detect_ci_provider,
|
detect_ci_provider,
|
||||||
download,
|
download,
|
||||||
find_compatible_wheel,
|
find_compatible_wheel,
|
||||||
|
find_uv,
|
||||||
|
free_thread_enable_313,
|
||||||
get_build_verbosity_extra_flags,
|
get_build_verbosity_extra_flags,
|
||||||
get_pip_version,
|
get_pip_version,
|
||||||
install_certifi_script,
|
install_certifi_script,
|
||||||
|
move_file,
|
||||||
prepare_command,
|
prepare_command,
|
||||||
read_python_configs,
|
read_python_configs,
|
||||||
shell,
|
shell,
|
||||||
@@ -46,6 +49,7 @@ from .util import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache(maxsize=None)
|
||||||
def get_macos_version() -> tuple[int, int]:
|
def get_macos_version() -> tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
|
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
|
||||||
@@ -57,9 +61,29 @@ def get_macos_version() -> tuple[int, int]:
|
|||||||
"""
|
"""
|
||||||
version_str, _, _ = platform.mac_ver()
|
version_str, _, _ = platform.mac_ver()
|
||||||
version = tuple(map(int, version_str.split(".")[:2]))
|
version = tuple(map(int, version_str.split(".")[:2]))
|
||||||
|
if (10, 15) < version < (11, 0):
|
||||||
|
# When built against an older macOS SDK, Python will report macOS 10.16
|
||||||
|
# instead of the real version.
|
||||||
|
version_str = call(
|
||||||
|
sys.executable,
|
||||||
|
"-sS",
|
||||||
|
"-c",
|
||||||
|
"import platform; print(platform.mac_ver()[0])",
|
||||||
|
env={"SYSTEM_VERSION_COMPAT": "0"},
|
||||||
|
capture_stdout=True,
|
||||||
|
)
|
||||||
|
version = tuple(map(int, version_str.split(".")[:2]))
|
||||||
return typing.cast(Tuple[int, int], version)
|
return typing.cast(Tuple[int, int], version)
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache(maxsize=None)
|
||||||
|
def get_test_macosx_deployment_target() -> str:
|
||||||
|
version = get_macos_version()
|
||||||
|
if version >= (11, 0):
|
||||||
|
return f"{version[0]}.0"
|
||||||
|
return f"{version[0]}.{version[1]}"
|
||||||
|
|
||||||
|
|
||||||
def get_macos_sdks() -> list[str]:
|
def get_macos_sdks() -> list[str]:
|
||||||
output = call("xcodebuild", "-showsdks", capture_stdout=True)
|
output = call("xcodebuild", "-showsdks", capture_stdout=True)
|
||||||
return [m.group(1) for m in re.finditer(r"-sdk (macosx\S+)", output)]
|
return [m.group(1) for m in re.finditer(r"-sdk (macosx\S+)", output)]
|
||||||
@@ -114,35 +138,44 @@ def get_python_configurations(
|
|||||||
return python_configurations
|
return python_configurations
|
||||||
|
|
||||||
|
|
||||||
def install_cpython(tmp: Path, version: str, url: str) -> Path:
|
def install_cpython(tmp: Path, version: str, url: str, free_threading: bool) -> Path:
|
||||||
installation_path = Path(f"/Library/Frameworks/Python.framework/Versions/{version}")
|
ft = "T" if free_threading else ""
|
||||||
|
installation_path = Path(f"/Library/Frameworks/Python{ft}.framework/Versions/{version}")
|
||||||
with FileLock(CIBW_CACHE_PATH / f"cpython{version}.lock"):
|
with FileLock(CIBW_CACHE_PATH / f"cpython{version}.lock"):
|
||||||
installed_system_packages = call("pkgutil", "--pkgs", capture_stdout=True).splitlines()
|
installed_system_packages = call("pkgutil", "--pkgs", capture_stdout=True).splitlines()
|
||||||
# if this version of python isn't installed, get it from python.org and install
|
# if this version of python isn't installed, get it from python.org and install
|
||||||
python_package_identifier = f"org.python.Python.PythonFramework-{version}"
|
python_package_identifier = f"org.python.Python.Python{ft}Framework-{version}"
|
||||||
if python_package_identifier not in installed_system_packages:
|
if python_package_identifier not in installed_system_packages:
|
||||||
if detect_ci_provider() is None:
|
if detect_ci_provider() is None:
|
||||||
# if running locally, we don't want to install CPython with sudo
|
# if running locally, we don't want to install CPython with sudo
|
||||||
# let the user know & provide a link to the installer
|
# let the user know & provide a link to the installer
|
||||||
print(
|
msg = (
|
||||||
f"Error: CPython {version} is not installed.\n"
|
f"Error: CPython {version} is not installed.\n"
|
||||||
"cibuildwheel will not perform system-wide installs when running outside of CI.\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"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}",
|
f"\nDownload link: {url}"
|
||||||
file=sys.stderr,
|
|
||||||
)
|
)
|
||||||
raise SystemExit(1)
|
raise errors.FatalError(msg)
|
||||||
pkg_path = tmp / "Python.pkg"
|
pkg_path = tmp / "Python.pkg"
|
||||||
# download the pkg
|
# download the pkg
|
||||||
download(url, pkg_path)
|
download(url, pkg_path)
|
||||||
# install
|
# install
|
||||||
call("sudo", "installer", "-pkg", pkg_path, "-target", "/")
|
args = []
|
||||||
|
if version.startswith("3.13"):
|
||||||
|
# Python 3.13 is the first version to have a free-threading option
|
||||||
|
args += ["-applyChoiceChangesXML", str(free_thread_enable_313.resolve())]
|
||||||
|
call("sudo", "installer", "-pkg", pkg_path, *args, "-target", "/")
|
||||||
pkg_path.unlink()
|
pkg_path.unlink()
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||||
call(installation_path / "bin" / "python3", install_certifi_script, env=env)
|
|
||||||
|
|
||||||
return installation_path / "bin" / "python3"
|
if free_threading:
|
||||||
|
call(installation_path / f"bin/python{version}t", "-m", "ensurepip", env=env)
|
||||||
|
call(installation_path / f"bin/python{version}t", install_certifi_script, env=env)
|
||||||
|
else:
|
||||||
|
call(installation_path / "bin/python3", install_certifi_script, env=env)
|
||||||
|
|
||||||
|
return installation_path / "bin" / (f"python{version}t" if free_threading else "python3")
|
||||||
|
|
||||||
|
|
||||||
def install_pypy(tmp: Path, url: str) -> Path:
|
def install_pypy(tmp: Path, url: str) -> Path:
|
||||||
@@ -166,22 +199,42 @@ def setup_python(
|
|||||||
dependency_constraint_flags: Sequence[PathOrStr],
|
dependency_constraint_flags: Sequence[PathOrStr],
|
||||||
environment: ParsedEnvironment,
|
environment: ParsedEnvironment,
|
||||||
build_frontend: BuildFrontendName,
|
build_frontend: BuildFrontendName,
|
||||||
) -> dict[str, str]:
|
) -> tuple[Path, dict[str, str]]:
|
||||||
|
if build_frontend == "build[uv]" and Version(python_configuration.version) < Version("3.8"):
|
||||||
|
build_frontend = "build"
|
||||||
|
|
||||||
|
uv_path = find_uv()
|
||||||
|
use_uv = build_frontend == "build[uv]" and Version(python_configuration.version) >= Version(
|
||||||
|
"3.8"
|
||||||
|
)
|
||||||
|
|
||||||
tmp.mkdir()
|
tmp.mkdir()
|
||||||
implementation_id = python_configuration.identifier.split("-")[0]
|
implementation_id = python_configuration.identifier.split("-")[0]
|
||||||
log.step(f"Installing Python {implementation_id}...")
|
log.step(f"Installing Python {implementation_id}...")
|
||||||
if implementation_id.startswith("cp"):
|
if implementation_id.startswith("cp"):
|
||||||
base_python = install_cpython(tmp, python_configuration.version, python_configuration.url)
|
free_threading = "t-macos" in python_configuration.identifier
|
||||||
|
base_python = install_cpython(
|
||||||
|
tmp, python_configuration.version, python_configuration.url, free_threading
|
||||||
|
)
|
||||||
|
|
||||||
elif implementation_id.startswith("pp"):
|
elif implementation_id.startswith("pp"):
|
||||||
base_python = install_pypy(tmp, python_configuration.url)
|
base_python = install_pypy(tmp, python_configuration.url)
|
||||||
else:
|
else:
|
||||||
msg = "Unknown Python implementation"
|
msg = "Unknown Python implementation"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
assert base_python.exists()
|
assert (
|
||||||
|
base_python.exists()
|
||||||
|
), f"{base_python.name} not found, has {list(base_python.parent.iterdir())}"
|
||||||
|
|
||||||
log.step("Setting up build environment...")
|
log.step("Setting up build environment...")
|
||||||
venv_path = tmp / "venv"
|
venv_path = tmp / "venv"
|
||||||
env = virtualenv(base_python, venv_path, dependency_constraint_flags)
|
env = virtualenv(
|
||||||
|
python_configuration.version,
|
||||||
|
base_python,
|
||||||
|
venv_path,
|
||||||
|
dependency_constraint_flags,
|
||||||
|
use_uv=use_uv,
|
||||||
|
)
|
||||||
venv_bin_path = venv_path / "bin"
|
venv_bin_path = venv_path / "bin"
|
||||||
assert venv_bin_path.exists()
|
assert venv_bin_path.exists()
|
||||||
# Fix issue with site.py setting the wrong `sys.prefix`, `sys.exec_prefix`,
|
# Fix issue with site.py setting the wrong `sys.prefix`, `sys.exec_prefix`,
|
||||||
@@ -197,43 +250,43 @@ def setup_python(
|
|||||||
|
|
||||||
# upgrade pip to the version matching our constraints
|
# upgrade pip to the version matching our constraints
|
||||||
# if necessary, reinstall it to ensure that it's available on PATH as 'pip'
|
# if necessary, reinstall it to ensure that it's available on PATH as 'pip'
|
||||||
call(
|
if build_frontend == "build[uv]":
|
||||||
"python",
|
assert uv_path is not None
|
||||||
"-m",
|
pip = [str(uv_path), "pip"]
|
||||||
"pip",
|
else:
|
||||||
"install",
|
pip = ["python", "-m", "pip"]
|
||||||
"--upgrade",
|
|
||||||
"pip",
|
if not use_uv:
|
||||||
*dependency_constraint_flags,
|
call(
|
||||||
env=env,
|
*pip,
|
||||||
cwd=venv_path,
|
"install",
|
||||||
)
|
"--upgrade",
|
||||||
|
"pip",
|
||||||
|
*dependency_constraint_flags,
|
||||||
|
env=env,
|
||||||
|
cwd=venv_path,
|
||||||
|
)
|
||||||
|
|
||||||
# Apply our environment after pip is ready
|
# Apply our environment after pip is ready
|
||||||
env = environment.as_dictionary(prev_environment=env)
|
env = environment.as_dictionary(prev_environment=env)
|
||||||
|
|
||||||
# check what pip version we're on
|
# check what pip version we're on
|
||||||
assert (venv_bin_path / "pip").exists()
|
if not use_uv:
|
||||||
call("which", "pip", env=env)
|
assert (venv_bin_path / "pip").exists()
|
||||||
call("pip", "--version", env=env)
|
call("which", "pip", env=env)
|
||||||
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
|
call("pip", "--version", env=env)
|
||||||
if which_pip != str(venv_bin_path / "pip"):
|
which_pip = call("which", "pip", env=env, capture_stdout=True).strip()
|
||||||
print(
|
if which_pip != str(venv_bin_path / "pip"):
|
||||||
"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.",
|
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."
|
||||||
file=sys.stderr,
|
raise errors.FatalError(msg)
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# check what Python version we're on
|
# check what Python version we're on
|
||||||
call("which", "python", env=env)
|
call("which", "python", env=env)
|
||||||
call("python", "--version", env=env)
|
call("python", "--version", env=env)
|
||||||
which_python = call("which", "python", env=env, capture_stdout=True).strip()
|
which_python = call("which", "python", env=env, capture_stdout=True).strip()
|
||||||
if which_python != str(venv_bin_path / "python"):
|
if which_python != str(venv_bin_path / "python"):
|
||||||
print(
|
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."
|
||||||
"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)
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
config_is_arm64 = python_configuration.identifier.endswith("arm64")
|
config_is_arm64 = python_configuration.identifier.endswith("arm64")
|
||||||
config_is_universal2 = python_configuration.identifier.endswith("universal2")
|
config_is_universal2 = python_configuration.identifier.endswith("universal2")
|
||||||
@@ -241,8 +294,25 @@ def setup_python(
|
|||||||
# Set MACOSX_DEPLOYMENT_TARGET, if the user didn't set it.
|
# Set MACOSX_DEPLOYMENT_TARGET, if the user didn't set it.
|
||||||
# For arm64, the minimal deployment target is 11.0.
|
# For arm64, the minimal deployment target is 11.0.
|
||||||
# On x86_64 (or universal2), use 10.9 as a default.
|
# On x86_64 (or universal2), use 10.9 as a default.
|
||||||
# PyPy defaults to 10.7, causing inconsistencies if it's left unset.
|
# CPython 3.13 needs 10.13.
|
||||||
env.setdefault("MACOSX_DEPLOYMENT_TARGET", "11.0" if config_is_arm64 else "10.9")
|
if config_is_arm64:
|
||||||
|
default_target = "11.0"
|
||||||
|
elif Version(python_configuration.version) >= Version("3.13"):
|
||||||
|
default_target = "10.13"
|
||||||
|
elif python_configuration.identifier.startswith("pp") and Version(
|
||||||
|
python_configuration.version
|
||||||
|
) >= Version("3.9"):
|
||||||
|
default_target = "10.15"
|
||||||
|
else:
|
||||||
|
default_target = "10.9"
|
||||||
|
env.setdefault("MACOSX_DEPLOYMENT_TARGET", default_target)
|
||||||
|
|
||||||
|
# This is a floor, it can't be set lower than the default_target.
|
||||||
|
if Version(env["MACOSX_DEPLOYMENT_TARGET"]) < Version(default_target):
|
||||||
|
log.warning(
|
||||||
|
f"Bumping MACOSX_DEPLOYMENT_TARGET ({env['MACOSX_DEPLOYMENT_TARGET']}) to the minimum required ({default_target})."
|
||||||
|
)
|
||||||
|
env["MACOSX_DEPLOYMENT_TARGET"] = default_target
|
||||||
|
|
||||||
if python_configuration.version not in {"3.6", "3.7"}:
|
if python_configuration.version not in {"3.6", "3.7"}:
|
||||||
if config_is_arm64:
|
if config_is_arm64:
|
||||||
@@ -301,10 +371,22 @@ def setup_python(
|
|||||||
*dependency_constraint_flags,
|
*dependency_constraint_flags,
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
|
elif build_frontend == "build[uv]":
|
||||||
|
assert uv_path is not None
|
||||||
|
call(
|
||||||
|
uv_path,
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"delocate",
|
||||||
|
"build[virtualenv, uv]",
|
||||||
|
*dependency_constraint_flags,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
assert_never(build_frontend)
|
assert_never(build_frontend)
|
||||||
|
|
||||||
return env
|
return base_python, env
|
||||||
|
|
||||||
|
|
||||||
def build(options: Options, tmp_path: Path) -> None:
|
def build(options: Options, tmp_path: Path) -> None:
|
||||||
@@ -333,6 +415,14 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
build_options = options.build_options(config.identifier)
|
build_options = options.build_options(config.identifier)
|
||||||
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
|
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
|
||||||
|
use_uv = build_frontend.name == "build[uv]" and Version(config.version) >= Version(
|
||||||
|
"3.8"
|
||||||
|
)
|
||||||
|
uv_path = find_uv()
|
||||||
|
if use_uv and uv_path is None:
|
||||||
|
msg = "uv not found"
|
||||||
|
raise AssertionError(msg)
|
||||||
|
pip = ["pip"] if not use_uv else [str(uv_path), "pip"]
|
||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
|
|
||||||
identifier_tmp_dir = tmp_path / config.identifier
|
identifier_tmp_dir = tmp_path / config.identifier
|
||||||
@@ -350,13 +440,15 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
build_options.dependency_constraints.get_for_python_version(config.version),
|
build_options.dependency_constraints.get_for_python_version(config.version),
|
||||||
]
|
]
|
||||||
|
|
||||||
env = setup_python(
|
base_python, env = setup_python(
|
||||||
identifier_tmp_dir / "build",
|
identifier_tmp_dir / "build",
|
||||||
config,
|
config,
|
||||||
dependency_constraint_flags,
|
dependency_constraint_flags,
|
||||||
build_options.environment,
|
build_options.environment,
|
||||||
build_frontend.name,
|
build_frontend.name,
|
||||||
)
|
)
|
||||||
|
if not use_uv:
|
||||||
|
pip_version = get_pip_version(env)
|
||||||
|
|
||||||
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
if compatible_wheel:
|
if compatible_wheel:
|
||||||
@@ -382,15 +474,14 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
extra_flags += build_frontend.args
|
extra_flags += build_frontend.args
|
||||||
|
|
||||||
build_env = env.copy()
|
build_env = env.copy()
|
||||||
build_env["VIRTUALENV_PIP"] = get_pip_version(env)
|
if not use_uv:
|
||||||
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
if build_options.dependency_constraints:
|
if build_options.dependency_constraints:
|
||||||
constraint_path = build_options.dependency_constraints.get_for_python_version(
|
constraint_path = build_options.dependency_constraints.get_for_python_version(
|
||||||
config.version
|
config.version
|
||||||
)
|
)
|
||||||
user_constraints = build_env.get("PIP_CONSTRAINT")
|
combine_constraints(
|
||||||
our_constraints = constraint_path.as_uri()
|
build_env, constraint_path, identifier_tmp_dir if use_uv else None
|
||||||
build_env["PIP_CONSTRAINT"] = " ".join(
|
|
||||||
c for c in [user_constraints, our_constraints] if c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if build_frontend.name == "pip":
|
if build_frontend.name == "pip":
|
||||||
@@ -408,10 +499,12 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
*extra_flags,
|
*extra_flags,
|
||||||
env=build_env,
|
env=build_env,
|
||||||
)
|
)
|
||||||
elif build_frontend.name == "build":
|
elif build_frontend.name == "build" or build_frontend.name == "build[uv]":
|
||||||
if not 0 <= build_options.build_verbosity < 2:
|
if not 0 <= build_options.build_verbosity < 2:
|
||||||
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
||||||
log.warning(msg)
|
log.warning(msg)
|
||||||
|
if use_uv and "--no-isolation" not in extra_flags and "-n" not in extra_flags:
|
||||||
|
extra_flags.append("--installer=uv")
|
||||||
call(
|
call(
|
||||||
"python",
|
"python",
|
||||||
"-m",
|
"-m",
|
||||||
@@ -430,7 +523,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
repaired_wheel_dir.mkdir()
|
repaired_wheel_dir.mkdir()
|
||||||
|
|
||||||
if built_wheel.name.endswith("none-any.whl"):
|
if built_wheel.name.endswith("none-any.whl"):
|
||||||
raise NonPlatformWheelError()
|
raise errors.NonPlatformWheelError()
|
||||||
|
|
||||||
if build_options.repair_command:
|
if build_options.repair_command:
|
||||||
log.step("Repairing wheel...")
|
log.step("Repairing wheel...")
|
||||||
@@ -455,7 +548,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
|
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
|
||||||
|
|
||||||
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
||||||
raise AlreadyBuiltWheelError(repaired_wheel.name)
|
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
|
||||||
|
|
||||||
log.step_end()
|
log.step_end()
|
||||||
|
|
||||||
@@ -541,15 +634,18 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
|
|
||||||
# set up a virtual environment to install and test from, to make sure
|
# set up a virtual environment to install and test from, to make sure
|
||||||
# there are no dependencies that were pulled in at build time.
|
# there are no dependencies that were pulled in at build time.
|
||||||
call("pip", "install", "virtualenv", *dependency_constraint_flags, env=env)
|
if not use_uv:
|
||||||
|
call("pip", "install", "virtualenv", *dependency_constraint_flags, env=env)
|
||||||
|
|
||||||
venv_dir = identifier_tmp_dir / f"venv-test-{testing_arch}"
|
venv_dir = identifier_tmp_dir / f"venv-test-{testing_arch}"
|
||||||
|
|
||||||
arch_prefix = []
|
arch_prefix = []
|
||||||
|
uv_arch_args = []
|
||||||
if testing_arch != machine_arch:
|
if testing_arch != machine_arch:
|
||||||
if machine_arch == "arm64" and testing_arch == "x86_64":
|
if machine_arch == "arm64" and testing_arch == "x86_64":
|
||||||
# rosetta2 will provide the emulation with just the arch prefix.
|
# rosetta2 will provide the emulation with just the arch prefix.
|
||||||
arch_prefix = ["arch", "-x86_64"]
|
arch_prefix = ["arch", "-x86_64"]
|
||||||
|
uv_arch_args = ["--python-platform", "x86_64-apple-darwin"]
|
||||||
else:
|
else:
|
||||||
msg = f"don't know how to emulate {testing_arch} on {machine_arch}"
|
msg = f"don't know how to emulate {testing_arch} on {machine_arch}"
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
@@ -558,17 +654,27 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
call_with_arch = functools.partial(call, *arch_prefix)
|
call_with_arch = functools.partial(call, *arch_prefix)
|
||||||
shell_with_arch = functools.partial(call, *arch_prefix, "/bin/sh", "-c")
|
shell_with_arch = functools.partial(call, *arch_prefix, "/bin/sh", "-c")
|
||||||
|
|
||||||
# Use --no-download to ensure determinism by using seed libraries
|
if use_uv:
|
||||||
# built into virtualenv
|
pip_install = functools.partial(call, *pip, "install", *uv_arch_args)
|
||||||
call_with_arch("python", "-m", "virtualenv", "--no-download", venv_dir, env=env)
|
call("uv", "venv", venv_dir, f"--python={base_python}", env=env)
|
||||||
|
else:
|
||||||
|
pip_install = functools.partial(call_with_arch, *pip, "install")
|
||||||
|
# Use pip version from the initial env to ensure determinism
|
||||||
|
venv_args = ["--no-periodic-update", f"--pip={pip_version}"]
|
||||||
|
# In Python<3.12, setuptools & wheel are installed as well, use virtualenv embedded ones
|
||||||
|
if Version(config.version) < Version("3.12"):
|
||||||
|
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
|
||||||
|
call_with_arch("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)
|
||||||
|
|
||||||
virtualenv_env = env.copy()
|
virtualenv_env = env.copy()
|
||||||
|
virtualenv_env["MACOSX_DEPLOYMENT_TARGET"] = get_test_macosx_deployment_target()
|
||||||
virtualenv_env["PATH"] = os.pathsep.join(
|
virtualenv_env["PATH"] = os.pathsep.join(
|
||||||
[
|
[
|
||||||
str(venv_dir / "bin"),
|
str(venv_dir / "bin"),
|
||||||
virtualenv_env["PATH"],
|
virtualenv_env["PATH"],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
||||||
|
|
||||||
# check that we are using the Python from the virtual environment
|
# check that we are using the Python from the virtual environment
|
||||||
call_with_arch("which", "python", env=virtualenv_env)
|
call_with_arch("which", "python", env=virtualenv_env)
|
||||||
@@ -599,18 +705,14 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
else:
|
else:
|
||||||
virtualenv_env_install_wheel = virtualenv_env
|
virtualenv_env_install_wheel = virtualenv_env
|
||||||
|
|
||||||
call_with_arch(
|
pip_install(
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
f"{repaired_wheel}{build_options.test_extras}",
|
f"{repaired_wheel}{build_options.test_extras}",
|
||||||
env=virtualenv_env_install_wheel,
|
env=virtualenv_env_install_wheel,
|
||||||
)
|
)
|
||||||
|
|
||||||
# test the wheel
|
# test the wheel
|
||||||
if build_options.test_requires:
|
if build_options.test_requires:
|
||||||
call_with_arch(
|
pip_install(
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
*build_options.test_requires,
|
*build_options.test_requires,
|
||||||
env=virtualenv_env_install_wheel,
|
env=virtualenv_env_install_wheel,
|
||||||
)
|
)
|
||||||
@@ -633,18 +735,18 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
|
|
||||||
# we're all done here; move it to output (overwrite existing)
|
# we're all done here; move it to output (overwrite existing)
|
||||||
if compatible_wheel is None:
|
if compatible_wheel is None:
|
||||||
with contextlib.suppress(FileNotFoundError):
|
output_wheel = build_options.output_dir.joinpath(repaired_wheel.name)
|
||||||
(build_options.output_dir / repaired_wheel.name).unlink()
|
moved_wheel = move_file(repaired_wheel, output_wheel)
|
||||||
|
if moved_wheel != output_wheel.resolve():
|
||||||
shutil.move(str(repaired_wheel), build_options.output_dir)
|
log.warning(
|
||||||
built_wheels.append(build_options.output_dir / repaired_wheel.name)
|
"{repaired_wheel} was moved to {moved_wheel} instead of {output_wheel}"
|
||||||
|
)
|
||||||
|
built_wheels.append(output_wheel)
|
||||||
|
|
||||||
# clean up
|
# clean up
|
||||||
shutil.rmtree(identifier_tmp_dir)
|
shutil.rmtree(identifier_tmp_dir)
|
||||||
|
|
||||||
log.build_end()
|
log.build_end()
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
log.step_end_with_error(
|
msg = f"Command {error.cmd} failed with code {error.returncode}. {error.stdout or ''}"
|
||||||
f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}"
|
raise errors.FatalError(msg) from error
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import sys
|
|||||||
import typing
|
import typing
|
||||||
import uuid
|
import uuid
|
||||||
from collections.abc import Mapping, Sequence
|
from collections.abc import Mapping, Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path, PurePath, PurePosixPath
|
from pathlib import Path, PurePath, PurePosixPath
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import IO, Dict, Literal
|
from typing import IO, Dict, Literal
|
||||||
@@ -32,7 +32,7 @@ ContainerEngineName = Literal["docker", "podman"]
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class OCIContainerEngineConfig:
|
class OCIContainerEngineConfig:
|
||||||
name: ContainerEngineName
|
name: ContainerEngineName
|
||||||
create_args: Sequence[str] = ()
|
create_args: tuple[str, ...] = field(default_factory=tuple)
|
||||||
disable_host_mount: bool = False
|
disable_host_mount: bool = False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -58,7 +58,7 @@ class OCIContainerEngineConfig:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return OCIContainerEngineConfig(
|
return OCIContainerEngineConfig(
|
||||||
name=name, create_args=create_args, disable_host_mount=disable_host_mount
|
name=name, create_args=tuple(create_args), disable_host_mount=disable_host_mount
|
||||||
)
|
)
|
||||||
|
|
||||||
def options_summary(self) -> str | dict[str, str]:
|
def options_summary(self) -> str | dict[str, str]:
|
||||||
|
|||||||
+217
-124
@@ -8,17 +8,16 @@ import difflib
|
|||||||
import enum
|
import enum
|
||||||
import functools
|
import functools
|
||||||
import shlex
|
import shlex
|
||||||
import sys
|
|
||||||
import textwrap
|
import textwrap
|
||||||
import traceback
|
from collections.abc import Generator, Iterable, Set
|
||||||
from collections.abc import Callable, Generator, Iterable, Iterator, Set
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Literal, Mapping, Sequence, TypedDict, Union # noqa: TID251
|
from typing import Any, Literal, Mapping, Sequence, Union # noqa: TID251
|
||||||
|
|
||||||
from packaging.specifiers import SpecifierSet
|
from packaging.specifiers import SpecifierSet
|
||||||
|
|
||||||
|
from . import errors
|
||||||
from ._compat import tomllib
|
from ._compat import tomllib
|
||||||
from ._compat.typing import NotRequired, assert_never
|
from ._compat.typing import assert_never
|
||||||
from .architecture import Architecture
|
from .architecture import Architecture
|
||||||
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
|
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
|
||||||
from .logger import log
|
from .logger import log
|
||||||
@@ -32,7 +31,6 @@ from .util import (
|
|||||||
BuildSelector,
|
BuildSelector,
|
||||||
DependencyConstraints,
|
DependencyConstraints,
|
||||||
TestSelector,
|
TestSelector,
|
||||||
cached_property,
|
|
||||||
format_safe,
|
format_safe,
|
||||||
resources_dir,
|
resources_dir,
|
||||||
selector_matches,
|
selector_matches,
|
||||||
@@ -52,6 +50,7 @@ class CommandLineArguments:
|
|||||||
print_build_identifiers: bool
|
print_build_identifiers: bool
|
||||||
allow_empty: bool
|
allow_empty: bool
|
||||||
prerelease_pythons: bool
|
prerelease_pythons: bool
|
||||||
|
debug_traceback: bool
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def defaults() -> CommandLineArguments:
|
def defaults() -> CommandLineArguments:
|
||||||
@@ -65,6 +64,7 @@ class CommandLineArguments:
|
|||||||
package_dir=Path("."),
|
package_dir=Path("."),
|
||||||
prerelease_pythons=False,
|
prerelease_pythons=False,
|
||||||
print_build_identifiers=False,
|
print_build_identifiers=False,
|
||||||
|
debug_traceback=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ class GlobalOptions:
|
|||||||
build_selector: BuildSelector
|
build_selector: BuildSelector
|
||||||
test_selector: TestSelector
|
test_selector: TestSelector
|
||||||
architectures: set[Architecture]
|
architectures: set[Architecture]
|
||||||
container_engine: OCIContainerEngineConfig
|
allow_empty: bool
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
@@ -95,6 +95,7 @@ class BuildOptions:
|
|||||||
build_verbosity: int
|
build_verbosity: int
|
||||||
build_frontend: BuildFrontendConfig | None
|
build_frontend: BuildFrontendConfig | None
|
||||||
config_settings: str
|
config_settings: str
|
||||||
|
container_engine: OCIContainerEngineConfig
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def package_dir(self) -> Path:
|
def package_dir(self) -> Path:
|
||||||
@@ -117,13 +118,16 @@ class BuildOptions:
|
|||||||
return self.globals.architectures
|
return self.globals.architectures
|
||||||
|
|
||||||
|
|
||||||
Setting = Union[Mapping[str, str], Sequence[str], str, int]
|
SettingLeaf = Union[str, int, bool]
|
||||||
|
SettingList = Sequence[SettingLeaf]
|
||||||
|
SettingTable = Mapping[str, Union[SettingLeaf, SettingList]]
|
||||||
|
SettingValue = Union[SettingTable, SettingList, SettingLeaf]
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class Override:
|
class Override:
|
||||||
select_pattern: str
|
select_pattern: str
|
||||||
options: dict[str, Setting]
|
options: dict[str, SettingValue]
|
||||||
inherit: dict[str, InheritRule]
|
inherit: dict[str, InheritRule]
|
||||||
|
|
||||||
|
|
||||||
@@ -136,22 +140,123 @@ DISALLOWED_OPTIONS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TableFmt(TypedDict):
|
class OptionsReaderError(errors.ConfigurationError):
|
||||||
# a format string, used with '.format', with `k` and `v` parameters
|
|
||||||
# e.g. "{k}={v}"
|
|
||||||
item: str
|
|
||||||
# the string that is inserted between items
|
|
||||||
# e.g. " "
|
|
||||||
sep: str
|
|
||||||
# a quoting function that, if supplied, is called to quote each value
|
|
||||||
# e.g. shlex.quote
|
|
||||||
quote: NotRequired[Callable[[str], str]]
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigOptionError(KeyError):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class OptionFormat:
|
||||||
|
"""
|
||||||
|
Base class for option format specifiers. These objects describe how values
|
||||||
|
can be parsed from rich TOML values and how they're merged together.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class NotSupported(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def format_list(self, value: SettingList) -> str: # noqa: ARG002
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
|
||||||
|
def format_table(self, table: SettingTable) -> str: # noqa: ARG002
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
|
||||||
|
def merge_values(self, before: str, after: str) -> str: # noqa: ARG002
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
|
||||||
|
|
||||||
|
class ListFormat(OptionFormat):
|
||||||
|
"""
|
||||||
|
A format that joins lists with a separator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, sep: str) -> None:
|
||||||
|
self.sep = sep
|
||||||
|
|
||||||
|
def format_list(self, value: SettingList) -> str:
|
||||||
|
return self.sep.join(str(v) for v in value)
|
||||||
|
|
||||||
|
def merge_values(self, before: str, after: str) -> str:
|
||||||
|
return f"{before}{self.sep}{after}"
|
||||||
|
|
||||||
|
|
||||||
|
class ShlexTableFormat(OptionFormat):
|
||||||
|
"""
|
||||||
|
The standard table format uses shlex.quote to quote values and shlex.split
|
||||||
|
to unquote and split them. When merging values, keys in before are
|
||||||
|
replaced by keys in after.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, sep: str = " ", pair_sep: str = "=", allow_merge: bool = True) -> None:
|
||||||
|
self.sep = sep
|
||||||
|
self.pair_sep = pair_sep
|
||||||
|
self.allow_merge = allow_merge
|
||||||
|
|
||||||
|
def format_table(self, table: SettingTable) -> str:
|
||||||
|
assignments: list[tuple[str, str]] = []
|
||||||
|
|
||||||
|
for k, v in table.items():
|
||||||
|
if shlex.split(k) != [k]:
|
||||||
|
msg = f"Invalid table key: {k}"
|
||||||
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
|
if isinstance(v, str):
|
||||||
|
assignments.append((k, v))
|
||||||
|
elif isinstance(v, Sequence):
|
||||||
|
for inner_v in v:
|
||||||
|
assignments.append((k, str(inner_v)))
|
||||||
|
else:
|
||||||
|
assignments.append((k, str(v)))
|
||||||
|
|
||||||
|
return self.sep.join(f"{k}{self.pair_sep}{shlex.quote(v)}" for k, v in assignments)
|
||||||
|
|
||||||
|
def merge_values(self, before: str, after: str) -> str:
|
||||||
|
if not self.allow_merge:
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
|
||||||
|
before_dict = self.parse_table(before)
|
||||||
|
after_dict = self.parse_table(after)
|
||||||
|
|
||||||
|
return self.format_table({**before_dict, **after_dict})
|
||||||
|
|
||||||
|
def parse_table(self, table: str) -> Mapping[str, str | Sequence[str]]:
|
||||||
|
assignments: list[tuple[str, str]] = []
|
||||||
|
|
||||||
|
for assignment_str in shlex.split(table):
|
||||||
|
key, sep, value = assignment_str.partition(self.pair_sep)
|
||||||
|
|
||||||
|
if not sep:
|
||||||
|
msg = f"malformed option with value {assignment_str!r}"
|
||||||
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
|
assignments.append((key, value))
|
||||||
|
|
||||||
|
result: dict[str, str | list[str]] = {}
|
||||||
|
|
||||||
|
for key, value in assignments:
|
||||||
|
if key in result:
|
||||||
|
existing_value = result[key]
|
||||||
|
if isinstance(existing_value, list):
|
||||||
|
result[key] = [*existing_value, value]
|
||||||
|
else:
|
||||||
|
result[key] = [existing_value, value]
|
||||||
|
else:
|
||||||
|
result[key] = value
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class EnvironmentFormat(OptionFormat):
|
||||||
|
"""
|
||||||
|
The environment format accepts a table of environment variables, where the
|
||||||
|
values may contain variables or command substitutions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def format_table(self, table: SettingTable) -> str:
|
||||||
|
return " ".join(f'{k}="{v}"' for k, v in table.items())
|
||||||
|
|
||||||
|
def merge_values(self, before: str, after: str) -> str:
|
||||||
|
return f"{before} {after}"
|
||||||
|
|
||||||
|
|
||||||
class InheritRule(enum.Enum):
|
class InheritRule(enum.Enum):
|
||||||
NONE = enum.auto()
|
NONE = enum.auto()
|
||||||
APPEND = enum.auto()
|
APPEND = enum.auto()
|
||||||
@@ -159,10 +264,9 @@ class InheritRule(enum.Enum):
|
|||||||
|
|
||||||
|
|
||||||
def _resolve_cascade(
|
def _resolve_cascade(
|
||||||
*pairs: tuple[Setting | None, InheritRule],
|
*pairs: tuple[SettingValue | None, InheritRule],
|
||||||
ignore_empty: bool = False,
|
ignore_empty: bool = False,
|
||||||
list_sep: str | None = None,
|
option_format: OptionFormat | None = None,
|
||||||
table_format: TableFmt | None = None,
|
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Given a cascade of values with inherit rules, resolve them into a single
|
Given a cascade of values with inherit rules, resolve them into a single
|
||||||
@@ -185,28 +289,16 @@ def _resolve_cascade(
|
|||||||
|
|
||||||
result: str | None = None
|
result: str | None = None
|
||||||
|
|
||||||
if table_format is not None:
|
|
||||||
merge_sep = table_format["sep"]
|
|
||||||
elif list_sep is not None:
|
|
||||||
merge_sep = list_sep
|
|
||||||
else:
|
|
||||||
merge_sep = None
|
|
||||||
|
|
||||||
for value, rule in pairs:
|
for value, rule in pairs:
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ignore_empty and not value:
|
if ignore_empty and not value and value is not False:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
value_string = _stringify_setting(value, list_sep, table_format)
|
value_string = _stringify_setting(value, option_format=option_format)
|
||||||
|
|
||||||
result = _merge_values(
|
result = _apply_inherit_rule(result, value_string, rule=rule, option_format=option_format)
|
||||||
result,
|
|
||||||
value_string,
|
|
||||||
rule=rule,
|
|
||||||
merge_sep=merge_sep,
|
|
||||||
)
|
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
msg = "a setting should at least have a default value"
|
msg = "a setting should at least have a default value"
|
||||||
@@ -216,7 +308,9 @@ def _resolve_cascade(
|
|||||||
|
|
||||||
|
|
||||||
# pylint: disable-next=inconsistent-return-statements
|
# pylint: disable-next=inconsistent-return-statements
|
||||||
def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep: str | None) -> str:
|
def _apply_inherit_rule(
|
||||||
|
before: str | None, after: str, rule: InheritRule, option_format: OptionFormat | None
|
||||||
|
) -> str:
|
||||||
if rule == InheritRule.NONE:
|
if rule == InheritRule.NONE:
|
||||||
return after
|
return after
|
||||||
|
|
||||||
@@ -229,36 +323,41 @@ def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep:
|
|||||||
# if after is an empty string, we shouldn't add any separator
|
# if after is an empty string, we shouldn't add any separator
|
||||||
return before
|
return before
|
||||||
|
|
||||||
if not merge_sep:
|
if not option_format:
|
||||||
msg = f"Don't know how to merge {before!r} and {after!r} with {rule}"
|
msg = f"Don't know how to merge {before!r} and {after!r} with {rule}"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
if rule == InheritRule.APPEND:
|
if rule == InheritRule.APPEND:
|
||||||
return f"{before}{merge_sep}{after}"
|
return option_format.merge_values(before, after)
|
||||||
elif rule == InheritRule.PREPEND:
|
elif rule == InheritRule.PREPEND:
|
||||||
return f"{after}{merge_sep}{before}"
|
return option_format.merge_values(after, before)
|
||||||
else:
|
else:
|
||||||
assert_never(rule)
|
assert_never(rule)
|
||||||
|
|
||||||
|
|
||||||
def _stringify_setting(
|
def _stringify_setting(
|
||||||
setting: Setting, list_sep: str | None, table_format: TableFmt | None
|
setting: SettingValue,
|
||||||
|
option_format: OptionFormat | None,
|
||||||
) -> str:
|
) -> str:
|
||||||
if isinstance(setting, Mapping):
|
if isinstance(setting, Mapping):
|
||||||
if table_format is None:
|
try:
|
||||||
|
if option_format is None:
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
return option_format.format_table(setting)
|
||||||
|
except OptionFormat.NotSupported:
|
||||||
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a table"
|
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a table"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg) from None
|
||||||
return table_format["sep"].join(
|
|
||||||
item for k, v in setting.items() for item in _inner_fmt(k, v, table_format)
|
|
||||||
)
|
|
||||||
|
|
||||||
if not isinstance(setting, str) and isinstance(setting, Sequence):
|
if not isinstance(setting, str) and isinstance(setting, Sequence):
|
||||||
if list_sep is None:
|
try:
|
||||||
|
if option_format is None:
|
||||||
|
raise OptionFormat.NotSupported
|
||||||
|
return option_format.format_list(setting)
|
||||||
|
except OptionFormat.NotSupported:
|
||||||
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a list"
|
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a list"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg) from None
|
||||||
return list_sep.join(setting)
|
|
||||||
|
|
||||||
if isinstance(setting, int):
|
if isinstance(setting, (bool, int)):
|
||||||
return str(setting)
|
return str(setting)
|
||||||
|
|
||||||
return setting
|
return setting
|
||||||
@@ -322,14 +421,14 @@ class OptionsReader:
|
|||||||
if config_overrides is not None:
|
if config_overrides is not None:
|
||||||
if not isinstance(config_overrides, list):
|
if not isinstance(config_overrides, list):
|
||||||
msg = "'tool.cibuildwheel.overrides' must be a list"
|
msg = "'tool.cibuildwheel.overrides' must be a list"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
for config_override in config_overrides:
|
for config_override in config_overrides:
|
||||||
select = config_override.pop("select", None)
|
select = config_override.pop("select", None)
|
||||||
|
|
||||||
if not select:
|
if not select:
|
||||||
msg = "'select' must be set in an override"
|
msg = "'select' must be set in an override"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
if isinstance(select, list):
|
if isinstance(select, list):
|
||||||
select = " ".join(select)
|
select = " ".join(select)
|
||||||
@@ -339,7 +438,7 @@ class OptionsReader:
|
|||||||
i in {"none", "append", "prepend"} for i in inherit.values()
|
i in {"none", "append", "prepend"} for i in inherit.values()
|
||||||
):
|
):
|
||||||
msg = "'inherit' must be a dict containing only {'none', 'append', 'prepend'} values"
|
msg = "'inherit' must be a dict containing only {'none', 'append', 'prepend'} values"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
inherit_enum = {k: InheritRule[v.upper()] for k, v in inherit.items()}
|
inherit_enum = {k: InheritRule[v.upper()] for k, v in inherit.items()}
|
||||||
|
|
||||||
@@ -357,7 +456,7 @@ class OptionsReader:
|
|||||||
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
||||||
if matches:
|
if matches:
|
||||||
msg += f" Perhaps you meant {matches[0]!r}?"
|
msg += f" Perhaps you meant {matches[0]!r}?"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
def _validate_platform_option(self, name: str) -> None:
|
def _validate_platform_option(self, name: str) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -367,7 +466,7 @@ class OptionsReader:
|
|||||||
disallowed_platform_options = self.disallow.get(self.platform, set())
|
disallowed_platform_options = self.disallow.get(self.platform, set())
|
||||||
if name in disallowed_platform_options:
|
if name in disallowed_platform_options:
|
||||||
msg = f"{name!r} is not allowed in {disallowed_platform_options}"
|
msg = f"{name!r} is not allowed in {disallowed_platform_options}"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
allowed_option_names = self.default_options.keys() | self.default_platform_options.keys()
|
allowed_option_names = self.default_options.keys() | self.default_platform_options.keys()
|
||||||
|
|
||||||
@@ -376,7 +475,7 @@ class OptionsReader:
|
|||||||
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
||||||
if matches:
|
if matches:
|
||||||
msg += f" Perhaps you meant {matches[0]!r}?"
|
msg += f" Perhaps you meant {matches[0]!r}?"
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
def _load_file(self, filename: Path) -> tuple[dict[str, Any], dict[str, Any]]:
|
def _load_file(self, filename: Path) -> tuple[dict[str, Any], dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
@@ -411,8 +510,7 @@ class OptionsReader:
|
|||||||
name: str,
|
name: str,
|
||||||
*,
|
*,
|
||||||
env_plat: bool = True,
|
env_plat: bool = True,
|
||||||
list_sep: str | None = None,
|
option_format: OptionFormat | None = None,
|
||||||
table_format: TableFmt | None = None,
|
|
||||||
ignore_empty: bool = False,
|
ignore_empty: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -428,7 +526,7 @@ class OptionsReader:
|
|||||||
|
|
||||||
if name not in self.default_options and name not in self.default_platform_options:
|
if name not in self.default_options and name not in self.default_platform_options:
|
||||||
msg = f"{name!r} must be in cibuildwheel/resources/defaults.toml file to be accessed."
|
msg = f"{name!r} must be in cibuildwheel/resources/defaults.toml file to be accessed."
|
||||||
raise ConfigOptionError(msg)
|
raise OptionsReaderError(msg)
|
||||||
|
|
||||||
# Environment variable form
|
# Environment variable form
|
||||||
envvar = f"CIBW_{name.upper().replace('-', '_')}"
|
envvar = f"CIBW_{name.upper().replace('-', '_')}"
|
||||||
@@ -448,26 +546,10 @@ class OptionsReader:
|
|||||||
(self.env.get(envvar), InheritRule.NONE),
|
(self.env.get(envvar), InheritRule.NONE),
|
||||||
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
|
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
|
||||||
ignore_empty=ignore_empty,
|
ignore_empty=ignore_empty,
|
||||||
list_sep=list_sep,
|
option_format=option_format,
|
||||||
table_format=table_format,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _inner_fmt(k: str, v: Any, table: TableFmt) -> Iterator[str]:
|
|
||||||
quote_function = table.get("quote", lambda a: a)
|
|
||||||
|
|
||||||
if isinstance(v, list):
|
|
||||||
for inner_v in v:
|
|
||||||
qv = quote_function(inner_v)
|
|
||||||
yield table["item"].format(k=k, v=qv)
|
|
||||||
elif isinstance(v, bool):
|
|
||||||
qv = quote_function(str(v))
|
|
||||||
yield table["item"].format(k=k, v=qv)
|
|
||||||
else:
|
|
||||||
qv = quote_function(v)
|
|
||||||
yield table["item"].format(k=k, v=qv)
|
|
||||||
|
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -501,7 +583,7 @@ class Options:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@cached_property
|
@functools.cached_property
|
||||||
def package_requires_python_str(self) -> str | None:
|
def package_requires_python_str(self) -> str | None:
|
||||||
args = self.command_line_arguments
|
args = self.command_line_arguments
|
||||||
return get_requires_python_str(Path(args.package_dir))
|
return get_requires_python_str(Path(args.package_dir))
|
||||||
@@ -512,9 +594,17 @@ class Options:
|
|||||||
package_dir = args.package_dir
|
package_dir = args.package_dir
|
||||||
output_dir = args.output_dir
|
output_dir = args.output_dir
|
||||||
|
|
||||||
build_config = self.reader.get("build", env_plat=False, list_sep=" ") or "*"
|
build_config = (
|
||||||
skip_config = self.reader.get("skip", env_plat=False, list_sep=" ")
|
self.reader.get("build", env_plat=False, option_format=ListFormat(sep=" ")) or "*"
|
||||||
test_skip = self.reader.get("test-skip", env_plat=False, list_sep=" ")
|
)
|
||||||
|
skip_config = self.reader.get("skip", env_plat=False, option_format=ListFormat(sep=" "))
|
||||||
|
test_skip = self.reader.get("test-skip", env_plat=False, option_format=ListFormat(sep=" "))
|
||||||
|
|
||||||
|
free_threaded_support = strtobool(
|
||||||
|
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
|
||||||
|
|
||||||
prerelease_pythons = args.prerelease_pythons or strtobool(
|
prerelease_pythons = args.prerelease_pythons or strtobool(
|
||||||
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
|
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
|
||||||
@@ -527,7 +617,7 @@ class Options:
|
|||||||
)
|
)
|
||||||
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
|
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
|
||||||
|
|
||||||
archs_config_str = args.archs or self.reader.get("archs", list_sep=" ")
|
archs_config_str = args.archs or self.reader.get("archs", option_format=ListFormat(sep=" "))
|
||||||
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
|
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
|
||||||
|
|
||||||
# Process `--only`
|
# Process `--only`
|
||||||
@@ -536,34 +626,24 @@ class Options:
|
|||||||
skip_config = ""
|
skip_config = ""
|
||||||
architectures = Architecture.all_archs(self.platform)
|
architectures = Architecture.all_archs(self.platform)
|
||||||
prerelease_pythons = True
|
prerelease_pythons = True
|
||||||
|
free_threaded_support = True
|
||||||
|
|
||||||
build_selector = BuildSelector(
|
build_selector = BuildSelector(
|
||||||
build_config=build_config,
|
build_config=build_config,
|
||||||
skip_config=skip_config,
|
skip_config=skip_config,
|
||||||
requires_python=requires_python,
|
requires_python=requires_python,
|
||||||
prerelease_pythons=prerelease_pythons,
|
prerelease_pythons=prerelease_pythons,
|
||||||
|
free_threaded_support=free_threaded_support,
|
||||||
)
|
)
|
||||||
test_selector = TestSelector(skip_config=test_skip)
|
test_selector = TestSelector(skip_config=test_skip)
|
||||||
|
|
||||||
container_engine_str = self.reader.get(
|
|
||||||
"container-engine",
|
|
||||||
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
container_engine = OCIContainerEngineConfig.from_config_string(container_engine_str)
|
|
||||||
except ValueError as e:
|
|
||||||
msg = f"cibuildwheel: Failed to parse container config. {e}"
|
|
||||||
print(msg, file=sys.stderr)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
return GlobalOptions(
|
return GlobalOptions(
|
||||||
package_dir=package_dir,
|
package_dir=package_dir,
|
||||||
output_dir=output_dir,
|
output_dir=output_dir,
|
||||||
build_selector=build_selector,
|
build_selector=build_selector,
|
||||||
test_selector=test_selector,
|
test_selector=test_selector,
|
||||||
architectures=architectures,
|
architectures=architectures,
|
||||||
container_engine=container_engine,
|
allow_empty=allow_empty,
|
||||||
)
|
)
|
||||||
|
|
||||||
def build_options(self, identifier: str | None) -> BuildOptions:
|
def build_options(self, identifier: str | None) -> BuildOptions:
|
||||||
@@ -572,30 +652,33 @@ class Options:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with self.reader.identifier(identifier):
|
with self.reader.identifier(identifier):
|
||||||
before_all = self.reader.get("before-all", list_sep=" && ")
|
before_all = self.reader.get("before-all", option_format=ListFormat(sep=" && "))
|
||||||
|
|
||||||
environment_config = self.reader.get(
|
environment_config = self.reader.get("environment", option_format=EnvironmentFormat())
|
||||||
"environment", table_format={"item": '{k}="{v}"', "sep": " "}
|
environment_pass = self.reader.get(
|
||||||
|
"environment-pass", option_format=ListFormat(sep=" ")
|
||||||
|
).split()
|
||||||
|
before_build = self.reader.get("before-build", option_format=ListFormat(sep=" && "))
|
||||||
|
repair_command = self.reader.get(
|
||||||
|
"repair-wheel-command", option_format=ListFormat(sep=" && ")
|
||||||
)
|
)
|
||||||
environment_pass = self.reader.get("environment-pass", list_sep=" ").split()
|
|
||||||
before_build = self.reader.get("before-build", list_sep=" && ")
|
|
||||||
repair_command = self.reader.get("repair-wheel-command", list_sep=" && ")
|
|
||||||
config_settings = self.reader.get(
|
config_settings = self.reader.get(
|
||||||
"config-settings",
|
"config-settings", option_format=ShlexTableFormat(sep=" ", pair_sep="=")
|
||||||
table_format={"item": "{k}={v}", "sep": " ", "quote": shlex.quote},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
dependency_versions = self.reader.get("dependency-versions")
|
dependency_versions = self.reader.get("dependency-versions")
|
||||||
test_command = self.reader.get("test-command", list_sep=" && ")
|
test_command = self.reader.get("test-command", option_format=ListFormat(sep=" && "))
|
||||||
before_test = self.reader.get("before-test", list_sep=" && ")
|
before_test = self.reader.get("before-test", option_format=ListFormat(sep=" && "))
|
||||||
test_requires = self.reader.get("test-requires", list_sep=" ").split()
|
test_requires = self.reader.get(
|
||||||
test_extras = self.reader.get("test-extras", list_sep=",")
|
"test-requires", option_format=ListFormat(sep=" ")
|
||||||
|
).split()
|
||||||
|
test_extras = self.reader.get("test-extras", option_format=ListFormat(sep=","))
|
||||||
build_verbosity_str = self.reader.get("build-verbosity")
|
build_verbosity_str = self.reader.get("build-verbosity")
|
||||||
|
|
||||||
build_frontend_str = self.reader.get(
|
build_frontend_str = self.reader.get(
|
||||||
"build-frontend",
|
"build-frontend",
|
||||||
env_plat=False,
|
env_plat=False,
|
||||||
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
|
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
|
||||||
)
|
)
|
||||||
build_frontend: BuildFrontendConfig | None
|
build_frontend: BuildFrontendConfig | None
|
||||||
if not build_frontend_str or build_frontend_str == "default":
|
if not build_frontend_str or build_frontend_str == "default":
|
||||||
@@ -604,18 +687,14 @@ class Options:
|
|||||||
try:
|
try:
|
||||||
build_frontend = BuildFrontendConfig.from_config_string(build_frontend_str)
|
build_frontend = BuildFrontendConfig.from_config_string(build_frontend_str)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print(f"cibuildwheel: {e}", file=sys.stderr)
|
msg = f"Failed to parse build frontend. {e}"
|
||||||
sys.exit(2)
|
raise errors.ConfigurationError(msg) from e
|
||||||
|
|
||||||
try:
|
try:
|
||||||
environment = parse_environment(environment_config)
|
environment = parse_environment(environment_config)
|
||||||
except (EnvironmentParseError, ValueError):
|
except (EnvironmentParseError, ValueError) as e:
|
||||||
print(
|
msg = f"Malformed environment option {environment_config!r}"
|
||||||
f"cibuildwheel: Malformed environment option {environment_config!r}",
|
raise errors.ConfigurationError(msg) from e
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
traceback.print_exc(None, sys.stderr)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
# Pass through environment variables
|
# Pass through environment variables
|
||||||
if self.platform == "linux":
|
if self.platform == "linux":
|
||||||
@@ -643,6 +722,8 @@ class Options:
|
|||||||
|
|
||||||
manylinux_images: dict[str, str] = {}
|
manylinux_images: dict[str, str] = {}
|
||||||
musllinux_images: dict[str, str] = {}
|
musllinux_images: dict[str, str] = {}
|
||||||
|
container_engine: OCIContainerEngineConfig | None = None
|
||||||
|
|
||||||
if self.platform == "linux":
|
if self.platform == "linux":
|
||||||
all_pinned_container_images = _get_pinned_container_images()
|
all_pinned_container_images = _get_pinned_container_images()
|
||||||
|
|
||||||
@@ -677,6 +758,17 @@ class Options:
|
|||||||
|
|
||||||
musllinux_images[build_platform] = image
|
musllinux_images[build_platform] = image
|
||||||
|
|
||||||
|
container_engine_str = self.reader.get(
|
||||||
|
"container-engine",
|
||||||
|
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
container_engine = OCIContainerEngineConfig.from_config_string(container_engine_str)
|
||||||
|
except ValueError as e:
|
||||||
|
msg = f"Failed to parse container config. {e}"
|
||||||
|
raise errors.ConfigurationError(msg) from e
|
||||||
|
|
||||||
return BuildOptions(
|
return BuildOptions(
|
||||||
globals=self.globals,
|
globals=self.globals,
|
||||||
test_command=test_command,
|
test_command=test_command,
|
||||||
@@ -693,6 +785,7 @@ class Options:
|
|||||||
musllinux_images=musllinux_images or None,
|
musllinux_images=musllinux_images or None,
|
||||||
build_frontend=build_frontend,
|
build_frontend=build_frontend,
|
||||||
config_settings=config_settings,
|
config_settings=config_settings,
|
||||||
|
container_engine=container_engine,
|
||||||
)
|
)
|
||||||
|
|
||||||
def check_for_invalid_configuration(self, identifiers: Iterable[str]) -> None:
|
def check_for_invalid_configuration(self, identifiers: Iterable[str]) -> None:
|
||||||
@@ -718,7 +811,7 @@ class Options:
|
|||||||
deprecated_selectors("CIBW_SKIP", build_selector.skip_config)
|
deprecated_selectors("CIBW_SKIP", build_selector.skip_config)
|
||||||
deprecated_selectors("CIBW_TEST_SKIP", test_selector.skip_config)
|
deprecated_selectors("CIBW_TEST_SKIP", test_selector.skip_config)
|
||||||
|
|
||||||
@cached_property
|
@functools.cached_property
|
||||||
def defaults(self) -> Options:
|
def defaults(self) -> Options:
|
||||||
return Options(
|
return Options(
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
@@ -854,6 +947,6 @@ def _get_pinned_container_images() -> Mapping[str, Mapping[str, str]]:
|
|||||||
def deprecated_selectors(name: str, selector: str, *, error: bool = False) -> None:
|
def deprecated_selectors(name: str, selector: str, *, error: bool = False) -> None:
|
||||||
if "p2" in selector or "p35" in selector:
|
if "p2" in selector or "p35" in selector:
|
||||||
msg = f"cibuildwheel 2.x no longer supports Python < 3.6. Please use the 1.x series or update {name}"
|
msg = f"cibuildwheel 2.x no longer supports Python < 3.6. Please use the 1.x series or update {name}"
|
||||||
print(msg, file=sys.stderr)
|
|
||||||
if error:
|
if error:
|
||||||
sys.exit(4)
|
raise errors.DeprecationError(msg)
|
||||||
|
log.warning(msg)
|
||||||
|
|||||||
@@ -39,10 +39,8 @@ def is_main(parent: ast.AST | None) -> bool:
|
|||||||
if len(mains) != 1:
|
if len(mains) != 1:
|
||||||
return False
|
return False
|
||||||
consts = {x for x in values if isinstance(x, ast.Name) and x.id == "__name__"}
|
consts = {x for x in values if isinstance(x, ast.Name) and x.id == "__name__"}
|
||||||
if len(consts) != 1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
return len(consts) == 1
|
||||||
|
|
||||||
|
|
||||||
class Analyzer(ast.NodeVisitor):
|
class Analyzer(ast.NodeVisitor):
|
||||||
|
|||||||
@@ -0,0 +1,399 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from collections.abc import Sequence, Set
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from filelock import FileLock
|
||||||
|
|
||||||
|
from . import errors
|
||||||
|
from .architecture import Architecture
|
||||||
|
from .environment import ParsedEnvironment
|
||||||
|
from .logger import log
|
||||||
|
from .options import Options
|
||||||
|
from .typing import PathOrStr
|
||||||
|
from .util import (
|
||||||
|
CIBW_CACHE_PATH,
|
||||||
|
BuildFrontendConfig,
|
||||||
|
BuildSelector,
|
||||||
|
call,
|
||||||
|
combine_constraints,
|
||||||
|
download,
|
||||||
|
ensure_node,
|
||||||
|
extract_zip,
|
||||||
|
find_compatible_wheel,
|
||||||
|
get_pip_version,
|
||||||
|
move_file,
|
||||||
|
prepare_command,
|
||||||
|
read_python_configs,
|
||||||
|
shell,
|
||||||
|
split_config_settings,
|
||||||
|
test_fail_cwd_file,
|
||||||
|
virtualenv,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PythonConfiguration:
|
||||||
|
version: str
|
||||||
|
identifier: str
|
||||||
|
pyodide_version: str
|
||||||
|
emscripten_version: str
|
||||||
|
node_version: str
|
||||||
|
|
||||||
|
|
||||||
|
def install_emscripten(tmp: Path, version: str) -> Path:
|
||||||
|
# We don't need to match the emsdk version to the version we install, but
|
||||||
|
# we do for stability
|
||||||
|
url = f"https://github.com/emscripten-core/emsdk/archive/refs/tags/{version}.zip"
|
||||||
|
installation_path = CIBW_CACHE_PATH / f"emsdk-{version}"
|
||||||
|
emsdk_path = installation_path / f"emsdk-{version}/emsdk"
|
||||||
|
emcc_path = installation_path / f"emsdk-{version}/upstream/emscripten/emcc"
|
||||||
|
with FileLock(f"{installation_path}.lock"):
|
||||||
|
if installation_path.exists():
|
||||||
|
return emcc_path
|
||||||
|
emsdk_zip = tmp / "emsdk.zip"
|
||||||
|
download(url, emsdk_zip)
|
||||||
|
installation_path.mkdir()
|
||||||
|
extract_zip(emsdk_zip, installation_path)
|
||||||
|
call(emsdk_path, "install", version)
|
||||||
|
call(emsdk_path, "activate", version)
|
||||||
|
|
||||||
|
return emcc_path
|
||||||
|
|
||||||
|
|
||||||
|
def install_xbuildenv(env: dict[str, str], pyodide_version: str) -> str:
|
||||||
|
pyodide_root = (
|
||||||
|
CIBW_CACHE_PATH
|
||||||
|
/ f".pyodide-xbuildenv-{pyodide_version}/{pyodide_version}/xbuildenv/pyodide-root"
|
||||||
|
)
|
||||||
|
with FileLock(CIBW_CACHE_PATH / "xbuildenv.lock"):
|
||||||
|
if pyodide_root.exists():
|
||||||
|
return str(pyodide_root)
|
||||||
|
|
||||||
|
# We don't want to mutate env but we need to delete any existing
|
||||||
|
# PYODIDE_ROOT so copy it first.
|
||||||
|
env = dict(env)
|
||||||
|
env.pop("PYODIDE_ROOT", None)
|
||||||
|
call(
|
||||||
|
"pyodide",
|
||||||
|
"xbuildenv",
|
||||||
|
"install",
|
||||||
|
pyodide_version,
|
||||||
|
env=env,
|
||||||
|
cwd=CIBW_CACHE_PATH,
|
||||||
|
)
|
||||||
|
return str(pyodide_root)
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_python(identifier: str) -> Path:
|
||||||
|
implementation_id = identifier.split("-")[0]
|
||||||
|
majorminor = implementation_id[len("cp") :]
|
||||||
|
version_info = (int(majorminor[0]), int(majorminor[1:]))
|
||||||
|
if version_info == sys.version_info[:2]:
|
||||||
|
return Path(sys.executable)
|
||||||
|
|
||||||
|
major_minor = ".".join(str(v) for v in version_info)
|
||||||
|
python_name = f"python{major_minor}"
|
||||||
|
which_python = shutil.which(python_name)
|
||||||
|
if which_python is None:
|
||||||
|
msg = f"CPython {major_minor} is not installed."
|
||||||
|
raise errors.FatalError(msg)
|
||||||
|
return Path(which_python)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_python(
|
||||||
|
tmp: Path,
|
||||||
|
python_configuration: PythonConfiguration,
|
||||||
|
dependency_constraint_flags: Sequence[PathOrStr],
|
||||||
|
environment: ParsedEnvironment,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
base_python = get_base_python(python_configuration.identifier)
|
||||||
|
|
||||||
|
log.step("Setting up build environment...")
|
||||||
|
venv_path = tmp / "venv"
|
||||||
|
env = virtualenv(python_configuration.version, base_python, venv_path, [], use_uv=False)
|
||||||
|
venv_bin_path = venv_path / "bin"
|
||||||
|
assert venv_bin_path.exists()
|
||||||
|
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||||
|
|
||||||
|
# upgrade pip to the version matching our constraints
|
||||||
|
# if necessary, reinstall it to ensure that it's available on PATH as 'pip'
|
||||||
|
call(
|
||||||
|
"python",
|
||||||
|
"-m",
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"pip",
|
||||||
|
*dependency_constraint_flags,
|
||||||
|
env=env,
|
||||||
|
cwd=venv_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
log.step("Installing build tools...")
|
||||||
|
call(
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"auditwheel-emscripten",
|
||||||
|
"build[virtualenv]",
|
||||||
|
"pyodide-build",
|
||||||
|
*dependency_constraint_flags,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
log.step("Installing emscripten...")
|
||||||
|
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)
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def get_python_configurations(
|
||||||
|
build_selector: BuildSelector,
|
||||||
|
architectures: Set[Architecture], # noqa: ARG001
|
||||||
|
) -> list[PythonConfiguration]:
|
||||||
|
full_python_configs = read_python_configs("pyodide")
|
||||||
|
|
||||||
|
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
|
||||||
|
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
||||||
|
return python_configurations
|
||||||
|
|
||||||
|
|
||||||
|
def build(options: Options, tmp_path: Path) -> None:
|
||||||
|
python_configurations = get_python_configurations(
|
||||||
|
options.globals.build_selector, options.globals.architectures
|
||||||
|
)
|
||||||
|
|
||||||
|
if not python_configurations:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
before_all_options_identifier = python_configurations[0].identifier
|
||||||
|
before_all_options = options.build_options(before_all_options_identifier)
|
||||||
|
|
||||||
|
if before_all_options.before_all:
|
||||||
|
log.step("Running before_all...")
|
||||||
|
env = before_all_options.environment.as_dictionary(prev_environment=os.environ)
|
||||||
|
before_all_prepared = prepare_command(
|
||||||
|
before_all_options.before_all, project=".", package=before_all_options.package_dir
|
||||||
|
)
|
||||||
|
shell(before_all_prepared, env=env)
|
||||||
|
|
||||||
|
built_wheels: list[Path] = []
|
||||||
|
|
||||||
|
for config in python_configurations:
|
||||||
|
build_options = options.build_options(config.identifier)
|
||||||
|
build_frontend = build_options.build_frontend or BuildFrontendConfig("build")
|
||||||
|
|
||||||
|
if build_frontend.name == "pip":
|
||||||
|
msg = "The pyodide platform doesn't support pip frontend"
|
||||||
|
raise errors.FatalError(msg)
|
||||||
|
|
||||||
|
log.build_start(config.identifier)
|
||||||
|
|
||||||
|
identifier_tmp_dir = tmp_path / config.identifier
|
||||||
|
built_wheel_dir = identifier_tmp_dir / "built_wheel"
|
||||||
|
repaired_wheel_dir = identifier_tmp_dir / "repaired_wheel"
|
||||||
|
identifier_tmp_dir.mkdir()
|
||||||
|
built_wheel_dir.mkdir()
|
||||||
|
repaired_wheel_dir.mkdir()
|
||||||
|
|
||||||
|
dependency_constraint_flags: Sequence[PathOrStr] = []
|
||||||
|
if build_options.dependency_constraints:
|
||||||
|
constraints_path = build_options.dependency_constraints.get_for_python_version(
|
||||||
|
config.version, variant="pyodide"
|
||||||
|
)
|
||||||
|
dependency_constraint_flags = ["-c", constraints_path]
|
||||||
|
|
||||||
|
env = setup_python(
|
||||||
|
identifier_tmp_dir / "build",
|
||||||
|
config,
|
||||||
|
dependency_constraint_flags,
|
||||||
|
build_options.environment,
|
||||||
|
)
|
||||||
|
pip_version = get_pip_version(env)
|
||||||
|
# The Pyodide command line runner mounts all directories in the host
|
||||||
|
# filesystem into the Pyodide file system, except for the custom
|
||||||
|
# file systems /dev, /lib, /proc, and /tmp. Mounting the mount
|
||||||
|
# points for alternate file systems causes some mysterious failure
|
||||||
|
# of the process (it just quits without any clear error).
|
||||||
|
#
|
||||||
|
# Because of this, by default Pyodide can't see anything under /tmp.
|
||||||
|
# This environment variable tells it also to mount our temp
|
||||||
|
# directory.
|
||||||
|
oldmounts = ""
|
||||||
|
extra_mounts = [str(identifier_tmp_dir)]
|
||||||
|
if str(Path(".").resolve()).startswith("/tmp"):
|
||||||
|
extra_mounts.append(str(Path(".").resolve()))
|
||||||
|
|
||||||
|
if "_PYODIDE_EXTRA_MOUNTS" in env:
|
||||||
|
oldmounts = env["_PYODIDE_EXTRA_MOUNTS"] + ":"
|
||||||
|
env["_PYODIDE_EXTRA_MOUNTS"] = oldmounts + ":".join(extra_mounts)
|
||||||
|
|
||||||
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
|
if compatible_wheel:
|
||||||
|
log.step_end()
|
||||||
|
print(
|
||||||
|
f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
|
||||||
|
)
|
||||||
|
built_wheel = compatible_wheel
|
||||||
|
else:
|
||||||
|
if build_options.before_build:
|
||||||
|
log.step("Running before_build...")
|
||||||
|
before_build_prepared = prepare_command(
|
||||||
|
build_options.before_build, project=".", package=build_options.package_dir
|
||||||
|
)
|
||||||
|
shell(before_build_prepared, env=env)
|
||||||
|
|
||||||
|
log.step("Building wheel...")
|
||||||
|
|
||||||
|
extra_flags = split_config_settings(build_options.config_settings, "build")
|
||||||
|
extra_flags += build_frontend.args
|
||||||
|
|
||||||
|
if not 0 <= build_options.build_verbosity < 2:
|
||||||
|
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
||||||
|
log.warning(msg)
|
||||||
|
|
||||||
|
build_env = env.copy()
|
||||||
|
if build_options.dependency_constraints:
|
||||||
|
combine_constraints(build_env, constraints_path, identifier_tmp_dir)
|
||||||
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
|
call(
|
||||||
|
"pyodide",
|
||||||
|
"build",
|
||||||
|
build_options.package_dir,
|
||||||
|
f"--outdir={built_wheel_dir}",
|
||||||
|
*extra_flags,
|
||||||
|
env=build_env,
|
||||||
|
)
|
||||||
|
built_wheel = next(built_wheel_dir.glob("*.whl"))
|
||||||
|
|
||||||
|
if built_wheel.name.endswith("none-any.whl"):
|
||||||
|
raise errors.NonPlatformWheelError()
|
||||||
|
|
||||||
|
if build_options.repair_command:
|
||||||
|
log.step("Repairing wheel...")
|
||||||
|
|
||||||
|
repair_command_prepared = prepare_command(
|
||||||
|
build_options.repair_command,
|
||||||
|
wheel=built_wheel,
|
||||||
|
dest_dir=repaired_wheel_dir,
|
||||||
|
)
|
||||||
|
shell(repair_command_prepared, env=env)
|
||||||
|
else:
|
||||||
|
shutil.move(str(built_wheel), repaired_wheel_dir)
|
||||||
|
|
||||||
|
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
|
||||||
|
|
||||||
|
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
||||||
|
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
|
||||||
|
|
||||||
|
if build_options.test_command and build_options.test_selector(config.identifier):
|
||||||
|
log.step("Testing wheel...")
|
||||||
|
|
||||||
|
venv_dir = identifier_tmp_dir / "venv-test"
|
||||||
|
# set up a virtual environment to install and test from, to make sure
|
||||||
|
# there are no dependencies that were pulled in at build time.
|
||||||
|
|
||||||
|
virtualenv_env = env.copy()
|
||||||
|
virtualenv_env["PATH"] = os.pathsep.join(
|
||||||
|
[
|
||||||
|
str(ensure_node(config.node_version)),
|
||||||
|
virtualenv_env["PATH"],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# pyodide venv uses virtualenv under the hood
|
||||||
|
# use the pip embedded with virtualenv & disable network updates
|
||||||
|
virtualenv_create_env = virtualenv_env.copy()
|
||||||
|
virtualenv_create_env["VIRTUALENV_PIP"] = pip_version
|
||||||
|
virtualenv_create_env["VIRTUALENV_NO_PERIODIC_UPDATE"] = "1"
|
||||||
|
|
||||||
|
call("pyodide", "venv", venv_dir, env=virtualenv_create_env)
|
||||||
|
|
||||||
|
virtualenv_env["PATH"] = os.pathsep.join(
|
||||||
|
[
|
||||||
|
str(venv_dir / "bin"),
|
||||||
|
virtualenv_env["PATH"],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
||||||
|
|
||||||
|
# check that we are using the Python from the virtual environment
|
||||||
|
call("which", "python", env=virtualenv_env)
|
||||||
|
|
||||||
|
if build_options.before_test:
|
||||||
|
before_test_prepared = prepare_command(
|
||||||
|
build_options.before_test,
|
||||||
|
project=".",
|
||||||
|
package=build_options.package_dir,
|
||||||
|
)
|
||||||
|
shell(before_test_prepared, env=virtualenv_env)
|
||||||
|
|
||||||
|
# install the wheel
|
||||||
|
call(
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
f"{repaired_wheel}{build_options.test_extras}",
|
||||||
|
env=virtualenv_env,
|
||||||
|
)
|
||||||
|
|
||||||
|
# test the wheel
|
||||||
|
if build_options.test_requires:
|
||||||
|
call("pip", "install", *build_options.test_requires, env=virtualenv_env)
|
||||||
|
|
||||||
|
# run the tests from a temp dir, with an absolute path in the command
|
||||||
|
# (this ensures that Python runs the tests against the installed wheel
|
||||||
|
# and not the repo code)
|
||||||
|
test_command_prepared = prepare_command(
|
||||||
|
build_options.test_command,
|
||||||
|
project=Path(".").resolve(),
|
||||||
|
package=build_options.package_dir.resolve(),
|
||||||
|
)
|
||||||
|
|
||||||
|
test_cwd = identifier_tmp_dir / "test_cwd"
|
||||||
|
test_cwd.mkdir(exist_ok=True)
|
||||||
|
(test_cwd / "test_fail.py").write_text(test_fail_cwd_file.read_text())
|
||||||
|
|
||||||
|
shell(test_command_prepared, cwd=test_cwd, env=virtualenv_env)
|
||||||
|
|
||||||
|
# we're all done here; move it to output (overwrite existing)
|
||||||
|
if compatible_wheel is None:
|
||||||
|
output_wheel = build_options.output_dir.joinpath(repaired_wheel.name)
|
||||||
|
moved_wheel = move_file(repaired_wheel, output_wheel)
|
||||||
|
if moved_wheel != output_wheel.resolve():
|
||||||
|
log.warning(
|
||||||
|
"{repaired_wheel} was moved to {moved_wheel} instead of {output_wheel}"
|
||||||
|
)
|
||||||
|
built_wheels.append(output_wheel)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
@@ -8,6 +8,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-manylinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-manylinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-manylinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-manylinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -16,6 +17,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-manylinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-manylinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-manylinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-manylinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-manylinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
|
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
|
||||||
{ identifier = "pp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/pp38-pypy38_pp73" },
|
{ 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 = "pp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||||
@@ -28,6 +30,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-manylinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-manylinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-manylinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-manylinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -36,6 +39,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-manylinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-manylinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-manylinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-manylinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-manylinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -44,6 +48,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-manylinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-manylinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-manylinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ 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 = "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 = "pp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
|
{ 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 = "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 = "pp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/pp39-pypy39_pp73" },
|
||||||
@@ -60,6 +65,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-musllinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-musllinux_x86_64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-musllinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-musllinux_x86_64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-musllinux_x86_64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-musllinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-musllinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-musllinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-musllinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-musllinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-musllinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -68,6 +74,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-musllinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-musllinux_i686", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-musllinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-musllinux_i686", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-musllinux_i686", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-musllinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-musllinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-musllinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-musllinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-musllinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-musllinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -76,6 +83,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-musllinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-musllinux_aarch64", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-musllinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-musllinux_aarch64", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-musllinux_aarch64", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-musllinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-musllinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-musllinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-musllinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-musllinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-musllinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -84,6 +92,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-musllinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-musllinux_ppc64le", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-musllinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ identifier = "cp312-musllinux_ppc64le", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
||||||
{ identifier = "cp313-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
{ identifier = "cp313-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313" },
|
||||||
|
{ identifier = "cp313t-musllinux_ppc64le", version = "3.13", path_str = "/opt/python/cp313-cp313t" },
|
||||||
{ identifier = "cp36-musllinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
{ identifier = "cp36-musllinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
|
||||||
{ identifier = "cp37-musllinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
{ identifier = "cp37-musllinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
|
||||||
{ identifier = "cp38-musllinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
{ identifier = "cp38-musllinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
|
||||||
@@ -92,6 +101,7 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-musllinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
{ identifier = "cp311-musllinux_s390x", version = "3.11", path_str = "/opt/python/cp311-cp311" },
|
||||||
{ identifier = "cp312-musllinux_s390x", version = "3.12", path_str = "/opt/python/cp312-cp312" },
|
{ 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 = "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" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[macos]
|
[macos]
|
||||||
@@ -110,19 +120,22 @@ python_configurations = [
|
|||||||
{ identifier = "cp311-macosx_x86_64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
|
{ identifier = "cp311-macosx_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_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 = "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.3/python-3.12.3-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.3/python-3.12.3-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.3/python-3.12.3-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.0b1-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.0b1-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.0b1-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 = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-osx64.tar.bz2" },
|
{ 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_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" },
|
||||||
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
|
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
|
||||||
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
|
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
|
||||||
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
|
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
|
||||||
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.16-macos_x86_64.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.16-macos_arm64.tar.bz2" },
|
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-macos_arm64.tar.bz2" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[windows]
|
[windows]
|
||||||
@@ -139,17 +152,25 @@ python_configurations = [
|
|||||||
{ identifier = "cp310-win_amd64", version = "3.10.11", arch = "64" },
|
{ identifier = "cp310-win_amd64", version = "3.10.11", arch = "64" },
|
||||||
{ identifier = "cp311-win32", version = "3.11.9", arch = "32" },
|
{ identifier = "cp311-win32", version = "3.11.9", arch = "32" },
|
||||||
{ identifier = "cp311-win_amd64", version = "3.11.9", arch = "64" },
|
{ identifier = "cp311-win_amd64", version = "3.11.9", arch = "64" },
|
||||||
{ identifier = "cp312-win32", version = "3.12.3", arch = "32" },
|
{ identifier = "cp312-win32", version = "3.12.5", arch = "32" },
|
||||||
{ identifier = "cp312-win_amd64", version = "3.12.3", arch = "64" },
|
{ identifier = "cp312-win_amd64", version = "3.12.5", arch = "64" },
|
||||||
{ identifier = "cp313-win32", version = "3.13.0-b1", arch = "32" },
|
{ identifier = "cp313-win32", version = "3.13.0-rc1", arch = "32" },
|
||||||
{ identifier = "cp313-win_amd64", version = "3.13.0-b1", arch = "64" },
|
{ 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 = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
|
{ identifier = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
|
||||||
{ identifier = "cp310-win_arm64", version = "3.10.11", arch = "ARM64" },
|
{ identifier = "cp310-win_arm64", version = "3.10.11", arch = "ARM64" },
|
||||||
{ identifier = "cp311-win_arm64", version = "3.11.9", arch = "ARM64" },
|
{ identifier = "cp311-win_arm64", version = "3.11.9", arch = "ARM64" },
|
||||||
{ identifier = "cp312-win_arm64", version = "3.12.3", arch = "ARM64" },
|
{ identifier = "cp312-win_arm64", version = "3.12.5", arch = "ARM64" },
|
||||||
{ identifier = "cp313-win_arm64", version = "3.13.0-b1", 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 = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-win64.zip" },
|
{ 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 = "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 = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
|
||||||
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.16-win64.zip" },
|
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-win64.zip" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[pyodide]
|
||||||
|
python_configurations = [
|
||||||
|
{ identifier = "cp312-pyodide_wasm32", version = "3.12.1", pyodide_version = "0.26.1", emscripten_version = "3.1.58", node_version = "v20" },
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -96,12 +96,13 @@
|
|||||||
},
|
},
|
||||||
"build-frontend": {
|
"build-frontend": {
|
||||||
"default": "default",
|
"default": "default",
|
||||||
"description": "Set the tool to use to build, either \"pip\" (default for now) or \"build\"",
|
"description": "Set the tool to use to build, either \"pip\" (default for now), \"build\", or \"build[uv]\"",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"enum": [
|
"enum": [
|
||||||
"pip",
|
"pip",
|
||||||
"build",
|
"build",
|
||||||
|
"build[uv]",
|
||||||
"default"
|
"default"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -113,6 +114,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^build; ?args:"
|
"pattern": "^build; ?args:"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^build\\[uv\\]; ?args:"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
@@ -123,7 +128,8 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"pip",
|
"pip",
|
||||||
"build"
|
"build",
|
||||||
|
"build[uv]"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"args": {
|
"args": {
|
||||||
@@ -255,6 +261,12 @@
|
|||||||
],
|
],
|
||||||
"title": "CIBW_ENVIRONMENT_PASS"
|
"title": "CIBW_ENVIRONMENT_PASS"
|
||||||
},
|
},
|
||||||
|
"free-threaded-support": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "The project supports free-threaded builds of Python (PEP703)",
|
||||||
|
"title": "CIBW_FREE_THREADED_SUPPORT"
|
||||||
|
},
|
||||||
"manylinux-aarch64-image": {
|
"manylinux-aarch64-image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specify alternative manylinux / musllinux container images",
|
"description": "Specify alternative manylinux / musllinux container images",
|
||||||
@@ -491,6 +503,9 @@
|
|||||||
"config-settings": {
|
"config-settings": {
|
||||||
"$ref": "#/properties/config-settings"
|
"$ref": "#/properties/config-settings"
|
||||||
},
|
},
|
||||||
|
"container-engine": {
|
||||||
|
"$ref": "#/properties/container-engine"
|
||||||
|
},
|
||||||
"dependency-versions": {
|
"dependency-versions": {
|
||||||
"$ref": "#/properties/dependency-versions"
|
"$ref": "#/properties/dependency-versions"
|
||||||
},
|
},
|
||||||
@@ -579,6 +594,9 @@
|
|||||||
"config-settings": {
|
"config-settings": {
|
||||||
"$ref": "#/properties/config-settings"
|
"$ref": "#/properties/config-settings"
|
||||||
},
|
},
|
||||||
|
"container-engine": {
|
||||||
|
"$ref": "#/properties/container-engine"
|
||||||
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"$ref": "#/properties/environment"
|
"$ref": "#/properties/environment"
|
||||||
},
|
},
|
||||||
@@ -753,6 +771,51 @@
|
|||||||
"$ref": "#/properties/test-requires"
|
"$ref": "#/properties/test-requires"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"pyodide": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"archs": {
|
||||||
|
"$ref": "#/properties/archs"
|
||||||
|
},
|
||||||
|
"before-all": {
|
||||||
|
"$ref": "#/properties/before-all"
|
||||||
|
},
|
||||||
|
"before-build": {
|
||||||
|
"$ref": "#/properties/before-build"
|
||||||
|
},
|
||||||
|
"before-test": {
|
||||||
|
"$ref": "#/properties/before-test"
|
||||||
|
},
|
||||||
|
"build-frontend": {
|
||||||
|
"$ref": "#/properties/build-frontend"
|
||||||
|
},
|
||||||
|
"build-verbosity": {
|
||||||
|
"$ref": "#/properties/build-verbosity"
|
||||||
|
},
|
||||||
|
"config-settings": {
|
||||||
|
"$ref": "#/properties/config-settings"
|
||||||
|
},
|
||||||
|
"dependency-versions": {
|
||||||
|
"$ref": "#/properties/dependency-versions"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"$ref": "#/properties/environment"
|
||||||
|
},
|
||||||
|
"repair-wheel-command": {
|
||||||
|
"$ref": "#/properties/repair-wheel-command"
|
||||||
|
},
|
||||||
|
"test-command": {
|
||||||
|
"$ref": "#/properties/test-command"
|
||||||
|
},
|
||||||
|
"test-extras": {
|
||||||
|
"$ref": "#/properties/test-extras"
|
||||||
|
},
|
||||||
|
"test-requires": {
|
||||||
|
"$ref": "#/properties/test-requires"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# This file was autogenerated by uv via the following command:
|
||||||
|
# nox -s update_constraints
|
||||||
|
annotated-types==0.7.0
|
||||||
|
# via pydantic
|
||||||
|
anyio==4.4.0
|
||||||
|
# via httpx
|
||||||
|
auditwheel-emscripten==0.0.16
|
||||||
|
# via pyodide-build
|
||||||
|
build==1.2.1
|
||||||
|
# via
|
||||||
|
# -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
|
# pyodide-build
|
||||||
|
certifi==2024.8.30
|
||||||
|
# via
|
||||||
|
# httpcore
|
||||||
|
# httpx
|
||||||
|
# requests
|
||||||
|
charset-normalizer==3.3.2
|
||||||
|
# via requests
|
||||||
|
click==8.1.7
|
||||||
|
# via typer
|
||||||
|
cloudpickle==3.0.0
|
||||||
|
# via loky
|
||||||
|
cmake==3.30.2
|
||||||
|
# via pyodide-build
|
||||||
|
distlib==0.3.8
|
||||||
|
# via virtualenv
|
||||||
|
filelock==3.15.4
|
||||||
|
# via virtualenv
|
||||||
|
h11==0.14.0
|
||||||
|
# via httpcore
|
||||||
|
httpcore==1.0.5
|
||||||
|
# via httpx
|
||||||
|
httpx==0.27.2
|
||||||
|
# via unearth
|
||||||
|
idna==3.8
|
||||||
|
# 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
|
||||||
|
# via
|
||||||
|
# auditwheel-emscripten
|
||||||
|
# build
|
||||||
|
# pyodide-build
|
||||||
|
# unearth
|
||||||
|
pip==24.2
|
||||||
|
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
|
platformdirs==4.2.2
|
||||||
|
# via virtualenv
|
||||||
|
pydantic==2.8.2
|
||||||
|
# via
|
||||||
|
# pyodide-build
|
||||||
|
# pyodide-lock
|
||||||
|
pydantic-core==2.20.1
|
||||||
|
# via pydantic
|
||||||
|
pygments==2.18.0
|
||||||
|
# via rich
|
||||||
|
pyodide-build==0.26.1
|
||||||
|
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||||
|
pyodide-cli==0.2.4
|
||||||
|
# via
|
||||||
|
# auditwheel-emscripten
|
||||||
|
# pyodide-build
|
||||||
|
pyodide-lock==0.1.0a6
|
||||||
|
# via pyodide-build
|
||||||
|
pyproject-hooks==1.1.0
|
||||||
|
# via build
|
||||||
|
pyyaml==6.0.2
|
||||||
|
# via pyodide-build
|
||||||
|
requests==2.32.3
|
||||||
|
# via pyodide-build
|
||||||
|
resolvelib==1.0.1
|
||||||
|
# via pyodide-build
|
||||||
|
rich==13.8.0
|
||||||
|
# via
|
||||||
|
# pyodide-build
|
||||||
|
# pyodide-cli
|
||||||
|
# typer
|
||||||
|
ruamel-yaml==0.18.6
|
||||||
|
# via pyodide-build
|
||||||
|
ruamel-yaml-clib==0.2.8
|
||||||
|
# via ruamel-yaml
|
||||||
|
shellingham==1.5.4
|
||||||
|
# via typer
|
||||||
|
sniffio==1.3.1
|
||||||
|
# via
|
||||||
|
# anyio
|
||||||
|
# httpx
|
||||||
|
typer==0.12.5
|
||||||
|
# via
|
||||||
|
# auditwheel-emscripten
|
||||||
|
# pyodide-build
|
||||||
|
# pyodide-cli
|
||||||
|
types-requests==2.32.0.20240712
|
||||||
|
# via pyodide-build
|
||||||
|
typing-extensions==4.12.2
|
||||||
|
# via
|
||||||
|
# pydantic
|
||||||
|
# pydantic-core
|
||||||
|
# typer
|
||||||
|
unearth==0.17.2
|
||||||
|
# via pyodide-build
|
||||||
|
urllib3==2.2.2
|
||||||
|
# via
|
||||||
|
# requests
|
||||||
|
# types-requests
|
||||||
|
virtualenv==20.26.3
|
||||||
|
# via
|
||||||
|
# build
|
||||||
|
# pyodide-build
|
||||||
|
wheel==0.44.0
|
||||||
|
# via
|
||||||
|
# auditwheel-emscripten
|
||||||
|
# pyodide-build
|
||||||
@@ -3,28 +3,32 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
importlib-metadata==7.1.0
|
importlib-metadata==8.4.0
|
||||||
# via build
|
# via build
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
zipp==3.18.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
zipp==3.20.1
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
|||||||
@@ -3,22 +3,26 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
|||||||
@@ -3,22 +3,26 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
|||||||
@@ -3,22 +3,26 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.1.1
|
build==1.1.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.12.2
|
filelock==3.12.2
|
||||||
@@ -19,6 +21,7 @@ packaging==24.0
|
|||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
platformdirs==4.0.0
|
platformdirs==4.0.0
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
@@ -30,6 +33,7 @@ typing-extensions==4.7.1
|
|||||||
# delocate
|
# delocate
|
||||||
# importlib-metadata
|
# importlib-metadata
|
||||||
# platformdirs
|
# platformdirs
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
zipp==3.15.0
|
zipp==3.15.0
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
|||||||
@@ -3,28 +3,32 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
importlib-metadata==7.1.0
|
importlib-metadata==8.4.0
|
||||||
# via build
|
# via build
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
zipp==3.18.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
zipp==3.20.1
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
|||||||
@@ -3,28 +3,32 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
importlib-metadata==7.1.0
|
importlib-metadata==8.4.0
|
||||||
# via build
|
# via build
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
zipp==3.18.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
zipp==3.20.1
|
||||||
# via importlib-metadata
|
# via importlib-metadata
|
||||||
|
|||||||
@@ -3,22 +3,26 @@
|
|||||||
altgraph==0.17.4
|
altgraph==0.17.4
|
||||||
# via macholib
|
# via macholib
|
||||||
build==1.2.1
|
build==1.2.1
|
||||||
delocate==0.11.0
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
delocate==0.12.0
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.14.0
|
filelock==3.15.4
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
macholib==1.16.3
|
macholib==1.16.3
|
||||||
# via delocate
|
# via delocate
|
||||||
packaging==24.0
|
packaging==24.1
|
||||||
# via
|
# via
|
||||||
# build
|
# build
|
||||||
# delocate
|
# delocate
|
||||||
pip==24.0
|
pip==24.2
|
||||||
platformdirs==4.2.1
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
platformdirs==4.2.2
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pyproject-hooks==1.1.0
|
pyproject-hooks==1.1.0
|
||||||
# via build
|
# via build
|
||||||
typing-extensions==4.11.0
|
typing-extensions==4.12.2
|
||||||
# via delocate
|
# via delocate
|
||||||
virtualenv==20.26.1
|
virtualenv==20.26.3
|
||||||
|
# via -r cibuildwheel/resources/constraints.in
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
build = "*"
|
build = "*"
|
||||||
skip = ""
|
skip = ""
|
||||||
test-skip = ""
|
test-skip = ""
|
||||||
|
free-threaded-support = false
|
||||||
|
|
||||||
archs = ["auto"]
|
archs = ["auto"]
|
||||||
build-frontend = "default"
|
build-frontend = "default"
|
||||||
@@ -45,3 +46,5 @@ repair-wheel-command = "auditwheel repair -w {dest_dir} {wheel}"
|
|||||||
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
|
repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}"
|
||||||
|
|
||||||
[tool.cibuildwheel.windows]
|
[tool.cibuildwheel.windows]
|
||||||
|
|
||||||
|
[tool.cibuildwheel.pyodide]
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>attributeSetting</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>choiceAttribute</key>
|
||||||
|
<string>selected</string>
|
||||||
|
<key>choiceIdentifier</key>
|
||||||
|
<string>org.python.Python.PythonTFramework-3.13</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
url = "https://nodejs.org/dist/"
|
||||||
|
v20 = "v20.17.0"
|
||||||
@@ -1,54 +1,54 @@
|
|||||||
[x86_64]
|
[x86_64]
|
||||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2024-04-29-76807b8
|
manylinux1 = quay.io/pypa/manylinux1_x86_64:2024-04-29-76807b8
|
||||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
|
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-05-10-7415d48
|
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-05-10-7415d48
|
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-05-10-7415d48
|
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.09.01-2
|
||||||
|
|
||||||
[i686]
|
[i686]
|
||||||
manylinux1 = quay.io/pypa/manylinux1_i686:2024-04-29-76807b8
|
manylinux1 = quay.io/pypa/manylinux1_i686:2024-04-29-76807b8
|
||||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
|
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-05-10-7415d48
|
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-05-10-7415d48
|
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.09.01-2
|
||||||
|
|
||||||
[pypy_x86_64]
|
[pypy_x86_64]
|
||||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
|
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-05-10-7415d48
|
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.09.01-2
|
||||||
|
|
||||||
[pypy_i686]
|
[pypy_i686]
|
||||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
|
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
|
||||||
|
|
||||||
[aarch64]
|
[aarch64]
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
|
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-05-10-7415d48
|
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-05-10-7415d48
|
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-05-10-7415d48
|
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.09.01-2
|
||||||
|
|
||||||
[ppc64le]
|
[ppc64le]
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2022-12-26-0d38463
|
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-05-10-7415d48
|
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-05-10-7415d48
|
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-05-10-7415d48
|
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.09.01-2
|
||||||
|
|
||||||
[s390x]
|
[s390x]
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2022-12-26-0d38463
|
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-05-10-7415d48
|
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-05-10-7415d48
|
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-05-10-7415d48
|
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.09.01-2
|
||||||
|
|
||||||
[pypy_aarch64]
|
[pypy_aarch64]
|
||||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024-05-10-7415d48
|
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.01-2
|
||||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
|
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-05-10-7415d48
|
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.01-2
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
version = "20.21.1"
|
py36 = { version = "20.21.1", url = "https://github.com/pypa/get-virtualenv/blob/20.21.1/public/virtualenv.pyz?raw=true" }
|
||||||
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" }
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ else:
|
|||||||
PathOrStr = Union[str, "os.PathLike[str]"]
|
PathOrStr = Union[str, "os.PathLike[str]"]
|
||||||
|
|
||||||
|
|
||||||
PlatformName = Literal["linux", "macos", "windows"]
|
PlatformName = Literal["linux", "macos", "windows", "pyodide"]
|
||||||
PLATFORMS: Final[set[PlatformName]] = {"linux", "macos", "windows"}
|
PLATFORMS: Final[set[PlatformName]] = {"linux", "macos", "windows", "pyodide"}
|
||||||
|
|
||||||
|
|
||||||
class GenericPythonConfiguration(Protocol):
|
class GenericPythonConfiguration(Protocol):
|
||||||
|
|||||||
+221
-89
@@ -6,21 +6,25 @@ import itertools
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
import shutil
|
||||||
import ssl
|
import ssl
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tarfile
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import typing
|
import typing
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Generator, Iterable, Mapping, Sequence
|
from collections.abc import Generator, Iterable, Mapping, MutableMapping, Sequence
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from functools import cached_property, lru_cache
|
from functools import lru_cache
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Any, ClassVar, Final, Literal, TextIO, TypeVar
|
from typing import Any, ClassVar, Final, Literal, TextIO, TypeVar
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
import bracex
|
import bracex
|
||||||
import certifi
|
import certifi
|
||||||
@@ -32,29 +36,33 @@ from packaging.version import Version
|
|||||||
from platformdirs import user_cache_path
|
from platformdirs import user_cache_path
|
||||||
|
|
||||||
from ._compat import tomllib
|
from ._compat import tomllib
|
||||||
|
from .architecture import Architecture
|
||||||
from .typing import PathOrStr, PlatformName
|
from .typing import PathOrStr, PlatformName
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"resources_dir",
|
|
||||||
"MANYLINUX_ARCHS",
|
"MANYLINUX_ARCHS",
|
||||||
"call",
|
"call",
|
||||||
"shell",
|
|
||||||
"find_compatible_wheel",
|
|
||||||
"format_safe",
|
|
||||||
"prepare_command",
|
|
||||||
"get_build_verbosity_extra_flags",
|
|
||||||
"read_python_configs",
|
|
||||||
"selector_matches",
|
|
||||||
"strtobool",
|
|
||||||
"cached_property",
|
|
||||||
"chdir",
|
"chdir",
|
||||||
|
"combine_constraints",
|
||||||
|
"find_compatible_wheel",
|
||||||
|
"find_uv",
|
||||||
|
"format_safe",
|
||||||
|
"get_build_verbosity_extra_flags",
|
||||||
|
"prepare_command",
|
||||||
|
"read_python_configs",
|
||||||
|
"resources_dir",
|
||||||
|
"selector_matches",
|
||||||
|
"shell",
|
||||||
"split_config_settings",
|
"split_config_settings",
|
||||||
|
"strtobool",
|
||||||
]
|
]
|
||||||
|
|
||||||
resources_dir: Final[Path] = Path(__file__).parent / "resources"
|
resources_dir: Final[Path] = Path(__file__).parent / "resources"
|
||||||
|
|
||||||
install_certifi_script: Final[Path] = resources_dir / "install_certifi.py"
|
install_certifi_script: Final[Path] = resources_dir / "install_certifi.py"
|
||||||
|
|
||||||
|
free_thread_enable_313: Final[Path] = resources_dir / "free-threaded-enable-313.xml"
|
||||||
|
|
||||||
test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py"
|
test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py"
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +203,9 @@ def get_build_verbosity_extra_flags(level: int) -> list[str]:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def split_config_settings(config_settings: str, frontend: Literal["pip", "build"]) -> list[str]:
|
def split_config_settings(
|
||||||
|
config_settings: str, frontend: Literal["pip", "build", "build[uv]"]
|
||||||
|
) -> list[str]:
|
||||||
config_settings_list = shlex.split(config_settings)
|
config_settings_list = shlex.split(config_settings)
|
||||||
s = "s" if frontend == "pip" else ""
|
s = "s" if frontend == "pip" else ""
|
||||||
return [f"--config-setting{s}={setting}" for setting in config_settings_list]
|
return [f"--config-setting{s}={setting}" for setting in config_settings_list]
|
||||||
@@ -238,13 +248,17 @@ class BuildSelector:
|
|||||||
requires_python: SpecifierSet | None = None
|
requires_python: SpecifierSet | None = None
|
||||||
|
|
||||||
# a pattern that skips prerelease versions, when include_prereleases is False.
|
# a pattern that skips prerelease versions, when include_prereleases is False.
|
||||||
PRERELEASE_SKIP: ClassVar[str] = "cp313-*"
|
PRERELEASE_SKIP: ClassVar[str] = ""
|
||||||
prerelease_pythons: bool = False
|
prerelease_pythons: bool = False
|
||||||
|
|
||||||
|
free_threaded_support: bool = False
|
||||||
|
|
||||||
def __call__(self, build_id: str) -> bool:
|
def __call__(self, build_id: str) -> bool:
|
||||||
# Filter build selectors by python_requires if set
|
# Filter build selectors by python_requires if set
|
||||||
if self.requires_python is not None:
|
if self.requires_python is not None:
|
||||||
py_ver_str = build_id.split("-")[0]
|
py_ver_str = build_id.split("-")[0]
|
||||||
|
if py_ver_str.endswith("t"):
|
||||||
|
py_ver_str = py_ver_str[:-1]
|
||||||
major = int(py_ver_str[2])
|
major = int(py_ver_str[2])
|
||||||
minor = int(py_ver_str[3:])
|
minor = int(py_ver_str[3:])
|
||||||
version = Version(f"{major}.{minor}.99")
|
version = Version(f"{major}.{minor}.99")
|
||||||
@@ -255,6 +269,10 @@ class BuildSelector:
|
|||||||
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
|
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
|
||||||
return False
|
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):
|
||||||
|
return False
|
||||||
|
|
||||||
should_build = selector_matches(self.build_config, build_id)
|
should_build = selector_matches(self.build_config, build_id)
|
||||||
should_skip = selector_matches(self.skip_config, build_id)
|
should_skip = selector_matches(self.skip_config, build_id)
|
||||||
|
|
||||||
@@ -266,6 +284,7 @@ class BuildSelector:
|
|||||||
"skip_config": self.skip_config,
|
"skip_config": self.skip_config,
|
||||||
"requires_python": str(self.requires_python),
|
"requires_python": str(self.requires_python),
|
||||||
"prerelease_pythons": self.prerelease_pythons,
|
"prerelease_pythons": self.prerelease_pythons,
|
||||||
|
"free_threaded_support": self.free_threaded_support,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -325,6 +344,55 @@ def download(url: str, dest: Path) -> None:
|
|||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_zip(zip_src: Path, dest: Path) -> None:
|
||||||
|
with ZipFile(zip_src) as zip_:
|
||||||
|
for zinfo in zip_.filelist:
|
||||||
|
zip_.extract(zinfo, dest)
|
||||||
|
|
||||||
|
# Set permissions to the same values as they were set in the archive
|
||||||
|
# We have to do this manually due to
|
||||||
|
# https://github.com/python/cpython/issues/59999
|
||||||
|
# But some files in the zipfile seem to have external_attr with 0
|
||||||
|
# permissions. In that case just use the default value???
|
||||||
|
permissions = (zinfo.external_attr >> 16) & 0o777
|
||||||
|
if permissions != 0:
|
||||||
|
dest.joinpath(zinfo.filename).chmod(permissions)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_tar(tar_src: Path, dest: Path) -> None:
|
||||||
|
with tarfile.open(tar_src) as tar_:
|
||||||
|
tar_.extraction_filter = getattr(tarfile, "tar_filter", (lambda member, _: member))
|
||||||
|
tar_.extractall(dest)
|
||||||
|
|
||||||
|
|
||||||
|
def move_file(src_file: Path, dst_file: Path) -> Path:
|
||||||
|
"""Moves a file safely while avoiding potential semantic confusion:
|
||||||
|
|
||||||
|
1. `dst_file` must point to the target filename, not a directory
|
||||||
|
2. `dst_file` will be overwritten if it already exists
|
||||||
|
3. any missing parent directories will be created
|
||||||
|
|
||||||
|
Returns the fully resolved Path of the resulting file.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotADirectoryError: If any part of the intermediate path to `dst_file` is an existing file
|
||||||
|
IsADirectoryError: If `dst_file` points directly to an existing directory
|
||||||
|
"""
|
||||||
|
src_file = src_file.resolve(strict=True)
|
||||||
|
dst_file = dst_file.resolve()
|
||||||
|
|
||||||
|
if dst_file.is_dir():
|
||||||
|
msg = "dst_file must be a valid target filename, not an existing directory."
|
||||||
|
raise IsADirectoryError(msg)
|
||||||
|
dst_file.unlink(missing_ok=True)
|
||||||
|
dst_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# using shutil.move() as Path.rename() is not guaranteed to work across filesystem boundaries
|
||||||
|
# explicit str() needed for Python 3.8
|
||||||
|
resulting_file = shutil.move(str(src_file), str(dst_file))
|
||||||
|
return Path(resulting_file).resolve(strict=True)
|
||||||
|
|
||||||
|
|
||||||
class DependencyConstraints:
|
class DependencyConstraints:
|
||||||
def __init__(self, base_file_path: Path):
|
def __init__(self, base_file_path: Path):
|
||||||
assert base_file_path.exists()
|
assert base_file_path.exists()
|
||||||
@@ -334,12 +402,14 @@ class DependencyConstraints:
|
|||||||
def with_defaults() -> DependencyConstraints:
|
def with_defaults() -> DependencyConstraints:
|
||||||
return DependencyConstraints(base_file_path=resources_dir / "constraints.txt")
|
return DependencyConstraints(base_file_path=resources_dir / "constraints.txt")
|
||||||
|
|
||||||
def get_for_python_version(self, version: str) -> Path:
|
def get_for_python_version(
|
||||||
|
self, version: str, *, variant: Literal["python", "pyodide"] = "python"
|
||||||
|
) -> Path:
|
||||||
version_parts = version.split(".")
|
version_parts = version.split(".")
|
||||||
|
|
||||||
# try to find a version-specific dependency file e.g. if
|
# try to find a version-specific dependency file e.g. if
|
||||||
# ./constraints.txt is the base, look for ./constraints-python36.txt
|
# ./constraints.txt is the base, look for ./constraints-python36.txt
|
||||||
specific_stem = self.base_file_path.stem + f"-python{version_parts[0]}{version_parts[1]}"
|
specific_stem = self.base_file_path.stem + f"-{variant}{version_parts[0]}{version_parts[1]}"
|
||||||
specific_name = specific_stem + self.base_file_path.suffix
|
specific_name = specific_stem + self.base_file_path.suffix
|
||||||
specific_file_path = self.base_file_path.with_name(specific_name)
|
specific_file_path = self.base_file_path.with_name(specific_name)
|
||||||
|
|
||||||
@@ -364,7 +434,7 @@ class DependencyConstraints:
|
|||||||
return self.base_file_path.name
|
return self.base_file_path.name
|
||||||
|
|
||||||
|
|
||||||
BuildFrontendName = Literal["pip", "build"]
|
BuildFrontendName = Literal["pip", "build", "build[uv]"]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -376,8 +446,8 @@ class BuildFrontendConfig:
|
|||||||
def from_config_string(config_string: str) -> BuildFrontendConfig:
|
def from_config_string(config_string: str) -> BuildFrontendConfig:
|
||||||
config_dict = parse_key_value_string(config_string, ["name"], ["args"])
|
config_dict = parse_key_value_string(config_string, ["name"], ["args"])
|
||||||
name = " ".join(config_dict["name"])
|
name = " ".join(config_dict["name"])
|
||||||
if name not in {"pip", "build"}:
|
if name not in {"pip", "build", "build[uv]"}:
|
||||||
msg = f"Unrecognised build frontend {name}, only 'pip' and 'build' are supported"
|
msg = f"Unrecognised build frontend {name!r}, only 'pip', 'build', and 'build[uv]' are supported"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
name = typing.cast(BuildFrontendName, name)
|
name = typing.cast(BuildFrontendName, name)
|
||||||
@@ -392,37 +462,6 @@ class BuildFrontendConfig:
|
|||||||
return {"name": self.name, "args": repr(self.args)}
|
return {"name": self.name, "args": repr(self.args)}
|
||||||
|
|
||||||
|
|
||||||
class NonPlatformWheelError(Exception):
|
|
||||||
def __init__(self) -> None:
|
|
||||||
message = textwrap.dedent(
|
|
||||||
"""
|
|
||||||
cibuildwheel: 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 expected a platform wheel, check your project configuration, or run
|
|
||||||
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class AlreadyBuiltWheelError(Exception):
|
|
||||||
def __init__(self, wheel_name: str) -> None:
|
|
||||||
message = textwrap.dedent(
|
|
||||||
f"""
|
|
||||||
cibuildwheel: Build failed because a wheel named {wheel_name} was already generated in the current run.
|
|
||||||
|
|
||||||
If you expected another wheel to be generated, check your project configuration, or run
|
|
||||||
cibuildwheel with CIBW_BUILD_VERBOSITY=1 to view build logs.
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
def strtobool(val: str) -> bool:
|
def strtobool(val: str) -> bool:
|
||||||
return val.lower() in {"y", "yes", "t", "true", "on", "1"}
|
return val.lower() in {"y", "yes", "t", "true", "on", "1"}
|
||||||
|
|
||||||
@@ -526,12 +565,47 @@ def get_pip_version(env: Mapping[str, str]) -> str:
|
|||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
@lru_cache(maxsize=None)
|
||||||
def _ensure_virtualenv() -> Path:
|
def ensure_node(major_version: str) -> Path:
|
||||||
|
input_file = resources_dir / "nodejs.toml"
|
||||||
|
with input_file.open("rb") as f:
|
||||||
|
loaded_file = tomllib.load(f)
|
||||||
|
version = str(loaded_file[major_version])
|
||||||
|
base_url = str(loaded_file["url"])
|
||||||
|
ext = "zip" if IS_WIN else "tar.xz"
|
||||||
|
platform = "win" if IS_WIN else ("darwin" if sys.platform.startswith("darwin") else "linux")
|
||||||
|
linux_arch = Architecture.native_arch("linux")
|
||||||
|
assert linux_arch is not None
|
||||||
|
arch = {"x86_64": "x64", "i686": "x86", "aarch64": "arm64"}.get(
|
||||||
|
linux_arch.value, linux_arch.value
|
||||||
|
)
|
||||||
|
name = f"node-{version}-{platform}-{arch}"
|
||||||
|
path = CIBW_CACHE_PATH / name
|
||||||
|
with FileLock(str(path) + ".lock"):
|
||||||
|
if not path.exists():
|
||||||
|
url = f"{base_url}{version}/{name}.{ext}"
|
||||||
|
with TemporaryDirectory() as tmp_path:
|
||||||
|
archive = Path(tmp_path) / f"{name}.{ext}"
|
||||||
|
download(url, archive)
|
||||||
|
if ext == "zip":
|
||||||
|
extract_zip(archive, path.parent)
|
||||||
|
else:
|
||||||
|
extract_tar(archive, path.parent)
|
||||||
|
assert path.exists()
|
||||||
|
if not IS_WIN:
|
||||||
|
return path / "bin"
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=None)
|
||||||
|
def _ensure_virtualenv(version: str) -> Path:
|
||||||
|
version_parts = version.split(".")
|
||||||
|
key = f"py{version_parts[0]}{version_parts[1]}"
|
||||||
input_file = resources_dir / "virtualenv.toml"
|
input_file = resources_dir / "virtualenv.toml"
|
||||||
with input_file.open("rb") as f:
|
with input_file.open("rb") as f:
|
||||||
loaded_file = tomllib.load(f)
|
loaded_file = tomllib.load(f)
|
||||||
version = str(loaded_file["version"])
|
configuration = loaded_file.get(key, loaded_file["default"])
|
||||||
url = str(loaded_file["url"])
|
version = str(configuration["version"])
|
||||||
|
url = str(configuration["url"])
|
||||||
path = CIBW_CACHE_PATH / f"virtualenv-{version}.pyz"
|
path = CIBW_CACHE_PATH / f"virtualenv-{version}.pyz"
|
||||||
with FileLock(str(path) + ".lock"):
|
with FileLock(str(path) + ".lock"):
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
@@ -587,48 +661,64 @@ def _parse_constraints_for_virtualenv(
|
|||||||
|
|
||||||
|
|
||||||
def virtualenv(
|
def virtualenv(
|
||||||
python: Path, venv_path: Path, dependency_constraint_flags: Sequence[PathOrStr]
|
version: str,
|
||||||
|
python: Path,
|
||||||
|
venv_path: Path,
|
||||||
|
dependency_constraint_flags: Sequence[PathOrStr],
|
||||||
|
*,
|
||||||
|
use_uv: bool,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Create a virtual environment. If `use_uv` is True,
|
||||||
|
dependency_constraint_flags are ignored since nothing is installed in the
|
||||||
|
venv. Otherwise, pip is installed, and setuptools + wheel if Python < 3.12.
|
||||||
|
"""
|
||||||
assert python.exists()
|
assert python.exists()
|
||||||
virtualenv_app = _ensure_virtualenv()
|
|
||||||
allowed_seed_packages = ["pip", "setuptools", "wheel"]
|
|
||||||
constraints = _parse_constraints_for_virtualenv(
|
|
||||||
allowed_seed_packages, dependency_constraint_flags
|
|
||||||
)
|
|
||||||
additional_flags: list[str] = []
|
|
||||||
for package in allowed_seed_packages:
|
|
||||||
if package in constraints:
|
|
||||||
additional_flags.append(f"--{package}={constraints[package]}")
|
|
||||||
else:
|
|
||||||
additional_flags.append(f"--no-{package}")
|
|
||||||
|
|
||||||
# Using symlinks to pre-installed seed packages is really the fastest way to get a virtual
|
if use_uv:
|
||||||
# environment. The initial cost is a bit higher but reusing is much faster.
|
call("uv", "venv", venv_path, "--python", python)
|
||||||
# Windows does not always allow symlinks so just disabling for now.
|
else:
|
||||||
# Requires pip>=19.3 so disabling for "embed" because this means we don't know what's the
|
virtualenv_app = _ensure_virtualenv(version)
|
||||||
# version of pip that will end-up installed.
|
allowed_seed_packages = ["pip", "setuptools", "wheel"]
|
||||||
# c.f. https://virtualenv.pypa.io/en/latest/cli_interface.html#section-seeder
|
constraints = _parse_constraints_for_virtualenv(
|
||||||
if (
|
allowed_seed_packages, dependency_constraint_flags
|
||||||
not IS_WIN
|
)
|
||||||
and constraints["pip"] != "embed"
|
additional_flags: list[str] = []
|
||||||
and Version(constraints["pip"]) >= Version("19.3")
|
for package in allowed_seed_packages:
|
||||||
):
|
if package in constraints:
|
||||||
additional_flags.append("--symlink-app-data")
|
additional_flags.append(f"--{package}={constraints[package]}")
|
||||||
|
else:
|
||||||
|
additional_flags.append(f"--no-{package}")
|
||||||
|
|
||||||
|
# Using symlinks to pre-installed seed packages is really the fastest way to get a virtual
|
||||||
|
# environment. The initial cost is a bit higher but reusing is much faster.
|
||||||
|
# Windows does not always allow symlinks so just disabling for now.
|
||||||
|
# Requires pip>=19.3 so disabling for "embed" because this means we don't know what's the
|
||||||
|
# version of pip that will end-up installed.
|
||||||
|
# c.f. https://virtualenv.pypa.io/en/latest/cli_interface.html#section-seeder
|
||||||
|
if (
|
||||||
|
not IS_WIN
|
||||||
|
and constraints["pip"] != "embed"
|
||||||
|
and Version(constraints["pip"]) >= Version("19.3")
|
||||||
|
):
|
||||||
|
additional_flags.append("--symlink-app-data")
|
||||||
|
|
||||||
|
call(
|
||||||
|
sys.executable,
|
||||||
|
"-sS", # just the stdlib, https://github.com/pypa/virtualenv/issues/2133#issuecomment-1003710125
|
||||||
|
virtualenv_app,
|
||||||
|
"--activators=",
|
||||||
|
"--no-periodic-update",
|
||||||
|
*additional_flags,
|
||||||
|
"--python",
|
||||||
|
python,
|
||||||
|
venv_path,
|
||||||
|
)
|
||||||
|
|
||||||
call(
|
|
||||||
sys.executable,
|
|
||||||
"-sS", # just the stdlib, https://github.com/pypa/virtualenv/issues/2133#issuecomment-1003710125
|
|
||||||
virtualenv_app,
|
|
||||||
"--activators=",
|
|
||||||
"--no-periodic-update",
|
|
||||||
*additional_flags,
|
|
||||||
"--python",
|
|
||||||
python,
|
|
||||||
venv_path,
|
|
||||||
)
|
|
||||||
paths = [str(venv_path), str(venv_path / "Scripts")] if IS_WIN else [str(venv_path / "bin")]
|
paths = [str(venv_path), str(venv_path / "Scripts")] if IS_WIN else [str(venv_path / "bin")]
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["PATH"] = os.pathsep.join([*paths, env["PATH"]])
|
env["PATH"] = os.pathsep.join([*paths, env["PATH"]])
|
||||||
|
env["VIRTUAL_ENV"] = str(venv_path)
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|
||||||
@@ -642,10 +732,13 @@ def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> T | None:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
interpreter, platform = identifier.split("-")
|
interpreter, platform = identifier.split("-")
|
||||||
|
free_threaded = interpreter.endswith("t")
|
||||||
|
if free_threaded:
|
||||||
|
interpreter = interpreter[:-1]
|
||||||
for wheel in wheels:
|
for wheel in wheels:
|
||||||
_, _, _, tags = parse_wheel_filename(wheel.name)
|
_, _, _, tags = parse_wheel_filename(wheel.name)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if tag.abi == "abi3":
|
if tag.abi == "abi3" and not free_threaded:
|
||||||
# ABI3 wheels must start with cp3 for impl and tag
|
# ABI3 wheels must start with cp3 for impl and tag
|
||||||
if not (interpreter.startswith("cp3") and tag.interpreter.startswith("cp3")):
|
if not (interpreter.startswith("cp3") and tag.interpreter.startswith("cp3")):
|
||||||
continue
|
continue
|
||||||
@@ -767,3 +860,42 @@ def parse_key_value_string(
|
|||||||
result[field_name] += values
|
result[field_name] += values
|
||||||
|
|
||||||
return dict(result)
|
return dict(result)
|
||||||
|
|
||||||
|
|
||||||
|
def find_uv() -> Path | None:
|
||||||
|
# Prefer uv in our environment
|
||||||
|
with contextlib.suppress(ImportError, FileNotFoundError):
|
||||||
|
# pylint: disable-next=import-outside-toplevel
|
||||||
|
from uv import find_uv_bin
|
||||||
|
|
||||||
|
return Path(find_uv_bin())
|
||||||
|
|
||||||
|
uv_on_path = shutil.which("uv")
|
||||||
|
return Path(uv_on_path) if uv_on_path else None
|
||||||
|
|
||||||
|
|
||||||
|
def combine_constraints(
|
||||||
|
env: MutableMapping[str, str], /, constraints_path: Path, tmp_dir: Path | None
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
This will workaround a bug in pip<=21.1.1 or uv<=0.2.0 if a tmp_dir is given.
|
||||||
|
If set to None, this will use the modern URI method.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if tmp_dir:
|
||||||
|
if " " in str(constraints_path):
|
||||||
|
assert " " not in str(tmp_dir)
|
||||||
|
tmp_file = tmp_dir / "constraints.txt"
|
||||||
|
tmp_file.write_bytes(constraints_path.read_bytes())
|
||||||
|
constraints_path = tmp_file
|
||||||
|
our_constraints = str(constraints_path)
|
||||||
|
else:
|
||||||
|
our_constraints = (
|
||||||
|
constraints_path.as_uri() if " " in str(constraints_path) else str(constraints_path)
|
||||||
|
)
|
||||||
|
|
||||||
|
user_constraints = env.get("PIP_CONSTRAINT")
|
||||||
|
|
||||||
|
env["UV_CONSTRAINT"] = env["PIP_CONSTRAINT"] = " ".join(
|
||||||
|
c for c in [our_constraints, user_constraints] if c
|
||||||
|
)
|
||||||
|
|||||||
+113
-95
@@ -4,18 +4,16 @@ import os
|
|||||||
import platform as platform_module
|
import platform as platform_module
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import textwrap
|
import textwrap
|
||||||
from collections.abc import MutableMapping, Sequence, Set
|
from collections.abc import MutableMapping, Sequence, Set
|
||||||
from contextlib import suppress
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from zipfile import ZipFile
|
|
||||||
|
|
||||||
from filelock import FileLock
|
from filelock import FileLock
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
|
||||||
|
from . import errors
|
||||||
from ._compat.typing import assert_never
|
from ._compat.typing import assert_never
|
||||||
from .architecture import Architecture
|
from .architecture import Architecture
|
||||||
from .environment import ParsedEnvironment
|
from .environment import ParsedEnvironment
|
||||||
@@ -24,16 +22,18 @@ from .options import Options
|
|||||||
from .typing import PathOrStr
|
from .typing import PathOrStr
|
||||||
from .util import (
|
from .util import (
|
||||||
CIBW_CACHE_PATH,
|
CIBW_CACHE_PATH,
|
||||||
AlreadyBuiltWheelError,
|
|
||||||
BuildFrontendConfig,
|
BuildFrontendConfig,
|
||||||
BuildFrontendName,
|
BuildFrontendName,
|
||||||
BuildSelector,
|
BuildSelector,
|
||||||
NonPlatformWheelError,
|
|
||||||
call,
|
call,
|
||||||
|
combine_constraints,
|
||||||
download,
|
download,
|
||||||
|
extract_zip,
|
||||||
find_compatible_wheel,
|
find_compatible_wheel,
|
||||||
|
find_uv,
|
||||||
get_build_verbosity_extra_flags,
|
get_build_verbosity_extra_flags,
|
||||||
get_pip_version,
|
get_pip_version,
|
||||||
|
move_file,
|
||||||
prepare_command,
|
prepare_command,
|
||||||
read_python_configs,
|
read_python_configs,
|
||||||
shell,
|
shell,
|
||||||
@@ -44,7 +44,9 @@ from .util import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_nuget_args(version: str, arch: str, output_directory: Path) -> list[str]:
|
def get_nuget_args(
|
||||||
|
version: str, arch: str, free_threaded: bool, output_directory: Path
|
||||||
|
) -> list[str]:
|
||||||
package_name = {
|
package_name = {
|
||||||
"32": "pythonx86",
|
"32": "pythonx86",
|
||||||
"64": "python",
|
"64": "python",
|
||||||
@@ -53,6 +55,8 @@ def get_nuget_args(version: str, arch: str, output_directory: Path) -> list[str]
|
|||||||
"x86": "pythonx86",
|
"x86": "pythonx86",
|
||||||
"AMD64": "python",
|
"AMD64": "python",
|
||||||
}[arch]
|
}[arch]
|
||||||
|
if free_threaded:
|
||||||
|
package_name = f"{package_name}-freethreaded"
|
||||||
return [
|
return [
|
||||||
package_name,
|
package_name,
|
||||||
"-Version",
|
"-Version",
|
||||||
@@ -92,11 +96,6 @@ def get_python_configurations(
|
|||||||
return python_configurations
|
return python_configurations
|
||||||
|
|
||||||
|
|
||||||
def extract_zip(zip_src: Path, dest: Path) -> None:
|
|
||||||
with ZipFile(zip_src) as zip_:
|
|
||||||
zip_.extractall(dest)
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
@lru_cache(maxsize=None)
|
||||||
def _ensure_nuget() -> Path:
|
def _ensure_nuget() -> Path:
|
||||||
nuget = CIBW_CACHE_PATH / "nuget.exe"
|
nuget = CIBW_CACHE_PATH / "nuget.exe"
|
||||||
@@ -106,11 +105,16 @@ def _ensure_nuget() -> Path:
|
|||||||
return nuget
|
return nuget
|
||||||
|
|
||||||
|
|
||||||
def install_cpython(version: str, arch: str) -> Path:
|
def install_cpython(configuration: PythonConfiguration, arch: str | None = None) -> Path:
|
||||||
|
version = configuration.version
|
||||||
|
free_threaded = "t-" in configuration.identifier
|
||||||
|
if arch is None:
|
||||||
|
arch = configuration.arch
|
||||||
base_output_dir = CIBW_CACHE_PATH / "nuget-cpython"
|
base_output_dir = CIBW_CACHE_PATH / "nuget-cpython"
|
||||||
nuget_args = get_nuget_args(version, arch, base_output_dir)
|
nuget_args = get_nuget_args(version, arch, free_threaded, base_output_dir)
|
||||||
installation_path = base_output_dir / (nuget_args[0] + "." + version) / "tools"
|
installation_path = base_output_dir / (nuget_args[0] + "." + version) / "tools"
|
||||||
with FileLock(str(base_output_dir) + f"-{version}-{arch}.lock"):
|
free_threaded_str = "-freethreaded" if free_threaded else ""
|
||||||
|
with FileLock(str(base_output_dir) + f"-{version}{free_threaded_str}-{arch}.lock"):
|
||||||
if not installation_path.exists():
|
if not installation_path.exists():
|
||||||
nuget = _ensure_nuget()
|
nuget = _ensure_nuget()
|
||||||
call(nuget, "install", *nuget_args)
|
call(nuget, "install", *nuget_args)
|
||||||
@@ -148,6 +152,16 @@ def setup_setuptools_cross_compile(
|
|||||||
# set the platform name
|
# set the platform name
|
||||||
map_plat = {"32": "win32", "64": "win-amd64", "ARM64": "win-arm64"}
|
map_plat = {"32": "win32", "64": "win-amd64", "ARM64": "win-arm64"}
|
||||||
plat_name = map_plat[python_configuration.arch]
|
plat_name = map_plat[python_configuration.arch]
|
||||||
|
|
||||||
|
# Set environment variable so that setuptools._distutils.get_platform()
|
||||||
|
# identifies the target, not the host
|
||||||
|
vscmd_arg_tgt_arch = {"32": "x86", "64": "x64", "ARM64": "arm64"}
|
||||||
|
current_tgt_arch = vscmd_arg_tgt_arch[python_configuration.arch]
|
||||||
|
if (env.get("VSCMD_ARG_TGT_ARCH") or current_tgt_arch) != current_tgt_arch:
|
||||||
|
msg = f"VSCMD_ARG_TGT_ARCH must be set to {current_tgt_arch!r}, got {env['VSCMD_ARG_TGT_ARCH']!r}. If you're setting up MSVC yourself (e.g. using vcvarsall.bat or msvc-dev-cmd), make sure to target the right architecture. Alternatively, run cibuildwheel without configuring MSVC, and let the build backend handle it."
|
||||||
|
raise errors.FatalError(msg)
|
||||||
|
env["VSCMD_ARG_TGT_ARCH"] = current_tgt_arch
|
||||||
|
|
||||||
# (This file must be default/locale encoding, so we can't pass 'encoding')
|
# (This file must be default/locale encoding, so we can't pass 'encoding')
|
||||||
distutils_cfg.write_text(
|
distutils_cfg.write_text(
|
||||||
textwrap.dedent(
|
textwrap.dedent(
|
||||||
@@ -217,25 +231,21 @@ def setup_python(
|
|||||||
dependency_constraint_flags: Sequence[PathOrStr],
|
dependency_constraint_flags: Sequence[PathOrStr],
|
||||||
environment: ParsedEnvironment,
|
environment: ParsedEnvironment,
|
||||||
build_frontend: BuildFrontendName,
|
build_frontend: BuildFrontendName,
|
||||||
) -> dict[str, str]:
|
) -> tuple[Path, dict[str, str]]:
|
||||||
tmp.mkdir()
|
tmp.mkdir()
|
||||||
implementation_id = python_configuration.identifier.split("-")[0]
|
implementation_id = python_configuration.identifier.split("-")[0]
|
||||||
python_libs_base = None
|
python_libs_base = None
|
||||||
log.step(f"Installing Python {implementation_id}...")
|
log.step(f"Installing Python {implementation_id}...")
|
||||||
if implementation_id.startswith("cp"):
|
if implementation_id.startswith("cp"):
|
||||||
native_arch = platform_module.machine()
|
native_arch = platform_module.machine()
|
||||||
|
base_python = install_cpython(python_configuration)
|
||||||
if python_configuration.arch == "ARM64" != native_arch:
|
if python_configuration.arch == "ARM64" != native_arch:
|
||||||
# To cross-compile for ARM64, we need a native CPython to run the
|
# To cross-compile for ARM64, we need a native CPython to run the
|
||||||
# build, and a copy of the ARM64 import libraries ('.\libs\*.lib')
|
# build, and a copy of the ARM64 import libraries ('.\libs\*.lib')
|
||||||
# for any extension modules.
|
# for any extension modules.
|
||||||
python_libs_base = install_cpython(
|
python_libs_base = base_python.parent / "libs"
|
||||||
python_configuration.version, python_configuration.arch
|
|
||||||
)
|
|
||||||
python_libs_base = python_libs_base.parent / "libs"
|
|
||||||
log.step(f"Installing native Python {native_arch} for cross-compilation...")
|
log.step(f"Installing native Python {native_arch} for cross-compilation...")
|
||||||
base_python = install_cpython(python_configuration.version, native_arch)
|
base_python = install_cpython(python_configuration, arch=native_arch)
|
||||||
else:
|
|
||||||
base_python = install_cpython(python_configuration.version, python_configuration.arch)
|
|
||||||
elif implementation_id.startswith("pp"):
|
elif implementation_id.startswith("pp"):
|
||||||
assert python_configuration.url is not None
|
assert python_configuration.url is not None
|
||||||
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
|
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
|
||||||
@@ -244,28 +254,36 @@ def setup_python(
|
|||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
assert base_python.exists()
|
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-")
|
||||||
|
)
|
||||||
|
uv_path = find_uv()
|
||||||
|
|
||||||
log.step("Setting up build environment...")
|
log.step("Setting up build environment...")
|
||||||
venv_path = tmp / "venv"
|
venv_path = tmp / "venv"
|
||||||
env = virtualenv(base_python, venv_path, dependency_constraint_flags)
|
env = virtualenv(
|
||||||
|
python_configuration.version,
|
||||||
|
base_python,
|
||||||
|
venv_path,
|
||||||
|
dependency_constraint_flags,
|
||||||
|
use_uv=use_uv,
|
||||||
|
)
|
||||||
|
|
||||||
# set up environment variables for run_with_env
|
# set up environment variables for run_with_env
|
||||||
env["PYTHON_VERSION"] = python_configuration.version
|
env["PYTHON_VERSION"] = python_configuration.version
|
||||||
env["PYTHON_ARCH"] = python_configuration.arch
|
env["PYTHON_ARCH"] = python_configuration.arch
|
||||||
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||||
|
|
||||||
# pip older than 21.3 builds executables such as pip.exe for x64 platform.
|
# upgrade pip to the version matching our constraints
|
||||||
# The first re-install of pip updates pip module but builds pip.exe using
|
# if necessary, reinstall it to ensure that it's available on PATH as 'pip.exe'
|
||||||
# the old pip which still generates x64 executable. But the second
|
if not use_uv:
|
||||||
# re-install uses updated pip and correctly builds pip.exe for the target.
|
|
||||||
# This can be removed once ARM64 Pythons (currently 3.9 and 3.10) bundle
|
|
||||||
# pip versions newer than 21.3.
|
|
||||||
if python_configuration.arch == "ARM64" and Version(get_pip_version(env)) < Version("21.3"):
|
|
||||||
call(
|
call(
|
||||||
"python",
|
"python",
|
||||||
"-m",
|
"-m",
|
||||||
"pip",
|
"pip",
|
||||||
"install",
|
"install",
|
||||||
"--force-reinstall",
|
|
||||||
"--upgrade",
|
"--upgrade",
|
||||||
"pip",
|
"pip",
|
||||||
*dependency_constraint_flags,
|
*dependency_constraint_flags,
|
||||||
@@ -273,20 +291,6 @@ def setup_python(
|
|||||||
cwd=venv_path,
|
cwd=venv_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
# upgrade pip to the version matching our constraints
|
|
||||||
# if necessary, reinstall it to ensure that it's available on PATH as 'pip.exe'
|
|
||||||
call(
|
|
||||||
"python",
|
|
||||||
"-m",
|
|
||||||
"pip",
|
|
||||||
"install",
|
|
||||||
"--upgrade",
|
|
||||||
"pip",
|
|
||||||
*dependency_constraint_flags,
|
|
||||||
env=env,
|
|
||||||
cwd=venv_path,
|
|
||||||
)
|
|
||||||
|
|
||||||
# update env with results from CIBW_ENVIRONMENT
|
# update env with results from CIBW_ENVIRONMENT
|
||||||
env = environment.as_dictionary(prev_environment=env)
|
env = environment.as_dictionary(prev_environment=env)
|
||||||
|
|
||||||
@@ -296,23 +300,18 @@ def setup_python(
|
|||||||
call("python", "-c", "\"import struct; print(struct.calcsize('P') * 8)\"", 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()
|
where_python = call("where", "python", env=env, capture_stdout=True).splitlines()[0].strip()
|
||||||
if where_python != str(venv_path / "Scripts" / "python.exe"):
|
if where_python != str(venv_path / "Scripts" / "python.exe"):
|
||||||
print(
|
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."
|
||||||
"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)
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# check what pip version we're on
|
# check what pip version we're on
|
||||||
assert (venv_path / "Scripts" / "pip.exe").exists()
|
if not use_uv:
|
||||||
where_pip = call("where", "pip", env=env, capture_stdout=True).splitlines()[0].strip()
|
assert (venv_path / "Scripts" / "pip.exe").exists()
|
||||||
if where_pip.strip() != str(venv_path / "Scripts" / "pip.exe"):
|
where_pip = call("where", "pip", env=env, capture_stdout=True).splitlines()[0].strip()
|
||||||
print(
|
if where_pip.strip() != str(venv_path / "Scripts" / "pip.exe"):
|
||||||
"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.",
|
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."
|
||||||
file=sys.stderr,
|
raise errors.FatalError(msg)
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
call("pip", "--version", env=env)
|
call("pip", "--version", env=env)
|
||||||
|
|
||||||
log.step("Installing build tools...")
|
log.step("Installing build tools...")
|
||||||
if build_frontend == "build":
|
if build_frontend == "build":
|
||||||
@@ -324,13 +323,24 @@ def setup_python(
|
|||||||
*dependency_constraint_flags,
|
*dependency_constraint_flags,
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
|
elif build_frontend == "build[uv]":
|
||||||
|
assert uv_path is not None
|
||||||
|
call(
|
||||||
|
uv_path,
|
||||||
|
"pip",
|
||||||
|
"install",
|
||||||
|
"--upgrade",
|
||||||
|
"build[virtualenv]",
|
||||||
|
*dependency_constraint_flags,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
if python_libs_base:
|
if python_libs_base:
|
||||||
# Set up the environment for various backends to enable cross-compilation
|
# Set up the environment for various backends to enable cross-compilation
|
||||||
setup_setuptools_cross_compile(tmp, python_configuration, python_libs_base, env)
|
setup_setuptools_cross_compile(tmp, python_configuration, python_libs_base, env)
|
||||||
setup_rust_cross_compile(tmp, python_configuration, python_libs_base, env)
|
setup_rust_cross_compile(tmp, python_configuration, python_libs_base, env)
|
||||||
|
|
||||||
return env
|
return base_python, env
|
||||||
|
|
||||||
|
|
||||||
def build(options: Options, tmp_path: Path) -> None:
|
def build(options: Options, tmp_path: Path) -> None:
|
||||||
@@ -358,6 +368,11 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
for config in python_configurations:
|
for config in python_configurations:
|
||||||
build_options = options.build_options(config.identifier)
|
build_options = options.build_options(config.identifier)
|
||||||
build_frontend = build_options.build_frontend or BuildFrontendConfig("pip")
|
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-")
|
||||||
|
)
|
||||||
log.build_start(config.identifier)
|
log.build_start(config.identifier)
|
||||||
|
|
||||||
identifier_tmp_dir = tmp_path / config.identifier
|
identifier_tmp_dir = tmp_path / config.identifier
|
||||||
@@ -373,13 +388,15 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
# install Python
|
# install Python
|
||||||
env = setup_python(
|
base_python, env = setup_python(
|
||||||
identifier_tmp_dir / "build",
|
identifier_tmp_dir / "build",
|
||||||
config,
|
config,
|
||||||
dependency_constraint_flags,
|
dependency_constraint_flags,
|
||||||
build_options.environment,
|
build_options.environment,
|
||||||
build_frontend.name,
|
build_frontend.name,
|
||||||
)
|
)
|
||||||
|
if not use_uv:
|
||||||
|
pip_version = get_pip_version(env)
|
||||||
|
|
||||||
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
|
||||||
if compatible_wheel:
|
if compatible_wheel:
|
||||||
@@ -408,26 +425,14 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
extra_flags += build_frontend.args
|
extra_flags += build_frontend.args
|
||||||
|
|
||||||
build_env = env.copy()
|
build_env = env.copy()
|
||||||
build_env["VIRTUALENV_PIP"] = get_pip_version(env)
|
if not use_uv:
|
||||||
|
build_env["VIRTUALENV_PIP"] = pip_version
|
||||||
|
|
||||||
if build_options.dependency_constraints:
|
if build_options.dependency_constraints:
|
||||||
constraints_path = build_options.dependency_constraints.get_for_python_version(
|
constraints_path = build_options.dependency_constraints.get_for_python_version(
|
||||||
config.version
|
config.version
|
||||||
)
|
)
|
||||||
# Bug in pip <= 21.1.3 - we can't have a space in the
|
combine_constraints(build_env, constraints_path, identifier_tmp_dir)
|
||||||
# constraints file, and pip doesn't support drive letters
|
|
||||||
# in uhi. After probably pip 21.2, we can use uri. For
|
|
||||||
# now, use a temporary file.
|
|
||||||
if " " in str(constraints_path):
|
|
||||||
assert " " not in str(identifier_tmp_dir)
|
|
||||||
tmp_file = identifier_tmp_dir / "constraints.txt"
|
|
||||||
tmp_file.write_bytes(constraints_path.read_bytes())
|
|
||||||
constraints_path = tmp_file
|
|
||||||
|
|
||||||
our_constraints = str(constraints_path)
|
|
||||||
user_constraints = build_env.get("PIP_CONSTRAINT")
|
|
||||||
build_env["PIP_CONSTRAINT"] = " ".join(
|
|
||||||
c for c in [our_constraints, user_constraints] if c
|
|
||||||
)
|
|
||||||
|
|
||||||
if build_frontend.name == "pip":
|
if build_frontend.name == "pip":
|
||||||
extra_flags += get_build_verbosity_extra_flags(build_options.build_verbosity)
|
extra_flags += get_build_verbosity_extra_flags(build_options.build_verbosity)
|
||||||
@@ -444,10 +449,12 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
*extra_flags,
|
*extra_flags,
|
||||||
env=build_env,
|
env=build_env,
|
||||||
)
|
)
|
||||||
elif build_frontend.name == "build":
|
elif build_frontend.name == "build" or build_frontend.name == "build[uv]":
|
||||||
if not 0 <= build_options.build_verbosity < 2:
|
if not 0 <= build_options.build_verbosity < 2:
|
||||||
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
msg = f"build_verbosity {build_options.build_verbosity} is not supported for build frontend. Ignoring."
|
||||||
log.warning(msg)
|
log.warning(msg)
|
||||||
|
if use_uv and "--no-isolation" not in extra_flags and "-n" not in extra_flags:
|
||||||
|
extra_flags.append("--installer=uv")
|
||||||
call(
|
call(
|
||||||
"python",
|
"python",
|
||||||
"-m",
|
"-m",
|
||||||
@@ -467,7 +474,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
repaired_wheel_dir.mkdir()
|
repaired_wheel_dir.mkdir()
|
||||||
|
|
||||||
if built_wheel.name.endswith("none-any.whl"):
|
if built_wheel.name.endswith("none-any.whl"):
|
||||||
raise NonPlatformWheelError()
|
raise errors.NonPlatformWheelError()
|
||||||
|
|
||||||
if build_options.repair_command:
|
if build_options.repair_command:
|
||||||
log.step("Repairing wheel...")
|
log.step("Repairing wheel...")
|
||||||
@@ -483,7 +490,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
|
repaired_wheel = next(repaired_wheel_dir.glob("*.whl"))
|
||||||
|
|
||||||
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
if repaired_wheel.name in {wheel.name for wheel in built_wheels}:
|
||||||
raise AlreadyBuiltWheelError(repaired_wheel.name)
|
raise errors.AlreadyBuiltWheelError(repaired_wheel.name)
|
||||||
|
|
||||||
test_selected = options.globals.test_selector(config.identifier)
|
test_selected = options.globals.test_selector(config.identifier)
|
||||||
if test_selected and config.arch == "ARM64" != platform_module.machine():
|
if test_selected and config.arch == "ARM64" != platform_module.machine():
|
||||||
@@ -501,12 +508,20 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
log.step("Testing wheel...")
|
log.step("Testing wheel...")
|
||||||
# set up a virtual environment to install and test from, to make sure
|
# set up a virtual environment to install and test from, to make sure
|
||||||
# there are no dependencies that were pulled in at build time.
|
# there are no dependencies that were pulled in at build time.
|
||||||
call("pip", "install", "virtualenv", *dependency_constraint_flags, env=env)
|
if not use_uv:
|
||||||
|
call("pip", "install", "virtualenv", *dependency_constraint_flags, env=env)
|
||||||
|
|
||||||
venv_dir = identifier_tmp_dir / "venv-test"
|
venv_dir = identifier_tmp_dir / "venv-test"
|
||||||
|
|
||||||
# Use --no-download to ensure determinism by using seed libraries
|
if use_uv:
|
||||||
# built into virtualenv
|
call("uv", "venv", venv_dir, f"--python={base_python}", env=env)
|
||||||
call("python", "-m", "virtualenv", "--no-download", venv_dir, env=env)
|
else:
|
||||||
|
# Use pip version from the initial env to ensure determinism
|
||||||
|
venv_args = ["--no-periodic-update", f"--pip={pip_version}"]
|
||||||
|
# In Python<3.12, setuptools & wheel are installed as well, use virtualenv embedded ones
|
||||||
|
if Version(config.version) < Version("3.12"):
|
||||||
|
venv_args.extend(("--setuptools=embed", "--wheel=embed"))
|
||||||
|
call("python", "-m", "virtualenv", *venv_args, venv_dir, env=env)
|
||||||
|
|
||||||
virtualenv_env = env.copy()
|
virtualenv_env = env.copy()
|
||||||
virtualenv_env["PATH"] = os.pathsep.join(
|
virtualenv_env["PATH"] = os.pathsep.join(
|
||||||
@@ -515,6 +530,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
virtualenv_env["PATH"],
|
virtualenv_env["PATH"],
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
virtualenv_env["VIRTUAL_ENV"] = str(venv_dir)
|
||||||
|
|
||||||
# check that we are using the Python from the virtual environment
|
# check that we are using the Python from the virtual environment
|
||||||
call("where", "python", env=virtualenv_env)
|
call("where", "python", env=virtualenv_env)
|
||||||
@@ -527,9 +543,11 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
shell(before_test_prepared, env=virtualenv_env)
|
shell(before_test_prepared, env=virtualenv_env)
|
||||||
|
|
||||||
|
pip = ["uv", "pip"] if use_uv else ["pip"]
|
||||||
|
|
||||||
# install the wheel
|
# install the wheel
|
||||||
call(
|
call(
|
||||||
"pip",
|
*pip,
|
||||||
"install",
|
"install",
|
||||||
str(repaired_wheel) + build_options.test_extras,
|
str(repaired_wheel) + build_options.test_extras,
|
||||||
env=virtualenv_env,
|
env=virtualenv_env,
|
||||||
@@ -537,7 +555,7 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
|
|
||||||
# test the wheel
|
# test the wheel
|
||||||
if build_options.test_requires:
|
if build_options.test_requires:
|
||||||
call("pip", "install", *build_options.test_requires, env=virtualenv_env)
|
call(*pip, "install", *build_options.test_requires, env=virtualenv_env)
|
||||||
|
|
||||||
# run the tests from a temp dir, with an absolute path in the command
|
# run the tests from a temp dir, with an absolute path in the command
|
||||||
# (this ensures that Python runs the tests against the installed wheel
|
# (this ensures that Python runs the tests against the installed wheel
|
||||||
@@ -556,11 +574,13 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
|
|
||||||
# we're all done here; move it to output (remove if already exists)
|
# we're all done here; move it to output (remove if already exists)
|
||||||
if compatible_wheel is None:
|
if compatible_wheel is None:
|
||||||
with suppress(FileNotFoundError):
|
output_wheel = build_options.output_dir.joinpath(repaired_wheel.name)
|
||||||
(build_options.output_dir / repaired_wheel.name).unlink()
|
moved_wheel = move_file(repaired_wheel, output_wheel)
|
||||||
|
if moved_wheel != output_wheel.resolve():
|
||||||
shutil.move(str(repaired_wheel), build_options.output_dir)
|
log.warning(
|
||||||
built_wheels.append(build_options.output_dir / repaired_wheel.name)
|
"{repaired_wheel} was moved to {moved_wheel} instead of {output_wheel}"
|
||||||
|
)
|
||||||
|
built_wheels.append(output_wheel)
|
||||||
|
|
||||||
# clean up
|
# clean up
|
||||||
# (we ignore errors because occasionally Windows fails to unlink a file and we
|
# (we ignore errors because occasionally Windows fails to unlink a file and we
|
||||||
@@ -569,7 +589,5 @@ def build(options: Options, tmp_path: Path) -> None:
|
|||||||
|
|
||||||
log.build_end()
|
log.build_end()
|
||||||
except subprocess.CalledProcessError as error:
|
except subprocess.CalledProcessError as error:
|
||||||
log.step_end_with_error(
|
msg = f"Command {error.cmd} failed with code {error.returncode}. {error.stdout or ''}"
|
||||||
f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}"
|
raise errors.FatalError(msg) from error
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|||||||
+70
-8
@@ -4,14 +4,76 @@ title: Changelog
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
### v2.20.0
|
||||||
|
|
||||||
|
- 🌟 CPython 3.13 wheels are now built by default - without the `CIBW_PRERELEASE_PYTHONS` flag. It's time to build and upload these wheels to PyPI! This release includes CPython 3.13.0rc1, which is guaranteed to be ABI compatible with the final release. Free-threading is still behind a flag/config option. (#1950)
|
||||||
|
- ✨ Provide a `CIBW_ALLOW_EMPTY` environment variable as an alternative to the command line flag. (#1937)
|
||||||
|
- 🐛 Don't use uv on PyPy3.8 on Windows, it stopped working starting in 0.2.25. Note that PyPy 3.8 is EoL. (#1868)
|
||||||
|
- 🛠 Set the `VSCMD_ARG_TGT_ARCH` variable based on target arch. (#1876)
|
||||||
|
- 🛠 Undo cleaner output on pytest 8-8.2 now that 8.3 is out. (#1943)
|
||||||
|
- 📚 Update examples to use Python 3.12 on host (cibuildwheel will require Python 3.11+ on the host machine starting in October 2024) (#1919)
|
||||||
|
|
||||||
|
|
||||||
|
### v2.19.2
|
||||||
|
|
||||||
|
- 🐛 Update manylinux2014 pins to versions that support past-EoL CentOS 7 mirrors. (#1917)
|
||||||
|
- 🐛 Support `--no-isolation` with `build[uv]` build-frontend. (#1889)
|
||||||
|
- 🛠 Provide attestations for releases at <https://github.com/pypa/cibuildwheel/attestations>. (#1916)
|
||||||
|
- 🛠 Provide CPython 3.13.0b3. (#1913)
|
||||||
|
- 🛠 Remove some workarounds now that pip 21.1 is available. (#1891, #1892)
|
||||||
|
- 📚 Remove nosetest from our docs. (#1821)
|
||||||
|
- 📚 Document the macOS ARM workaround for 3.8 on GHA. (#1871)
|
||||||
|
- 📚 GitLab CI + macOS is now a supported platform with an example. (#1911)
|
||||||
|
|
||||||
|
|
||||||
|
### v2.19.1
|
||||||
|
|
||||||
|
- 🐛 Don't require setup-python on GHA for Pyodide (#1868)
|
||||||
|
- 🐛 Specify full python path for uv (fixes issue in 0.2.10 & 0.2.11) (#1881)
|
||||||
|
- 🛠 Update for pip 24.1b2 on CPython 3.13. (#1879)
|
||||||
|
- 🛠 Fix a warning in our schema generation script. (#1866)
|
||||||
|
- 🛠 Cleaner output on pytest 8-8.2. (#1865)
|
||||||
|
|
||||||
|
|
||||||
|
### v2.19.0
|
||||||
|
|
||||||
|
See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more info on new features!
|
||||||
|
|
||||||
|
- 🌟 Add Pyodide platform. Set with `--platform pyodide` or `CIBW_PLATFORM: pyodide` on Linux with a host Python 3.12 to build WebAssembly wheels. Not accepted on PyPI currently, but usable directly in a website using Pyodide, for live docs, etc. (#1456, #1859)
|
||||||
|
- 🌟 Add `build[uv]` backend, which will take a pre-existing uv install (or install `cibuildwheel[uv]`) and use `uv` for all environment setup and installs on Python 3.8+. This is significantly faster in most cases. (#1856)
|
||||||
|
- ✨ Add free-threaded macOS builds and update CPython to 3.13.0b2. (#1854)
|
||||||
|
- 🐛 Issue copying a wheel to a non-existent output dir fixed. (#1851, #1862)
|
||||||
|
- 🐛 Better determinism for the test environment seeding. (#1835)
|
||||||
|
- 🛠 `VIRTUAL_ENV` variable now set. (#1842)
|
||||||
|
- 🛠 Remove a pip<21.3 workaround. (#1842)
|
||||||
|
- 🛠 Error handling was refactored to use exceptions. (#1719)
|
||||||
|
- 🛠 Hardcoded paths in tests avoided. (#1834)
|
||||||
|
- 🛠 Single Python tests made more generic. (#1835)
|
||||||
|
- 🛠 Sped up our ci by splitting up emulation tests. (#1839)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### v2.18.1
|
||||||
|
|
||||||
|
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
|
||||||
|
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
|
||||||
|
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
|
||||||
|
- 🛠 Significant improvements and modernization to our noxfile. (#1823)
|
||||||
|
- 🛠 Use pylint's new GitHub Actions reporter instead of a custom matcher. (#1823)
|
||||||
|
- 🛠 Unpin virtualenv updates for Python 3.7+ (#1830)
|
||||||
|
- 🐛 Fix running linux tests from Windows or macOS ARM. (#1788)
|
||||||
|
- 📚 Fix our documentation build. (#1821)
|
||||||
|
|
||||||
|
|
||||||
### v2.18.0
|
### v2.18.0
|
||||||
|
|
||||||
_12 May 2024_
|
_12 May 2024_
|
||||||
|
|
||||||
- ✨ Adds CPython 3.13 support, under the prerelease flag [CIBW_PRERELEASE_PYTHONS](https://cibuildwheel.pypa.io/en/stable/options/#prerelease-pythons). This version of cibuildwheel uses 3.13.0b1. Free-threading mode is not available yet, waiting on official binaries (planned for beta 2) and pip support.
|
- ✨ Adds CPython 3.13 support, under the prerelease flag [CIBW_PRERELEASE_PYTHONS](https://cibuildwheel.pypa.io/en/stable/options/#prerelease-pythons). This version of cibuildwheel uses 3.13.0b1. Free-threading mode is not available yet (#1657), waiting on official binaries (planned for beta 2) and pip support.
|
||||||
|
|
||||||
While CPython is in beta, the ABI can change, so your wheels might not be compatible with the final release. For this reason, we don't recommend distributing wheels until RC1, at which point 3.13 will be available in cibuildwheel without the flag. (#1816)
|
_While CPython is in beta, the ABI can change, so your wheels might not be compatible with the final release. For this reason, we don't recommend distributing wheels until RC1, at which point 3.13 will be available in cibuildwheel without the flag._ (#1815)
|
||||||
- ✨ Musllinux now defaults to `musllinux_1_2`. You can set the older `manylinux_1_1` via config if needed. (#1817)
|
|
||||||
|
- ✨ Musllinux now defaults to `musllinux_1_2`. You can set the older `musllinux_1_1` via config if needed. (#1817)
|
||||||
- 🛠 No longer pre-seed setuptools/wheel in virtual environments (#1819)
|
- 🛠 No longer pre-seed setuptools/wheel in virtual environments (#1819)
|
||||||
- 🛠 Respect the constraints file when building with pip, matching build (#1818)
|
- 🛠 Respect the constraints file when building with pip, matching build (#1818)
|
||||||
- 🛠 Use uv to compile our pinned dependencies, 10x faster and doesn't require special setup (#1778)
|
- 🛠 Use uv to compile our pinned dependencies, 10x faster and doesn't require special setup (#1778)
|
||||||
@@ -26,14 +88,14 @@ _12 May 2024_
|
|||||||
_11 March 2024_
|
_11 March 2024_
|
||||||
|
|
||||||
- 🌟 Adds the ability to inherit configuration in TOML overrides. This makes certain configurations much simpler. If you're overriding an option like `before-build` or `environment`, and you just want to add an extra command or environment variable, you can just append (or prepend) to the previous config. See [the docs](https://cibuildwheel.pypa.io/en/stable/options/#inherit) for more information. (#1730)
|
- 🌟 Adds the ability to inherit configuration in TOML overrides. This makes certain configurations much simpler. If you're overriding an option like `before-build` or `environment`, and you just want to add an extra command or environment variable, you can just append (or prepend) to the previous config. See [the docs](https://cibuildwheel.pypa.io/en/stable/options/#inherit) for more information. (#1730)
|
||||||
- 🌟 Adds official support for native arm64 macOS GitHub runners. To use them, just specify `macos-14` as an `os` of your job in your workflow file. You can also keep `macos-13` in your build matrix to build x86_64. Check out the new [GitHub Actions example config](https://cibuildwheel.pypa.io/en/stable/setup/#github-actions).
|
- 🌟 Adds official support for native `arm64` macOS GitHub runners. To use them, just specify `macos-14` as an `os` of your job in your workflow file. You can also keep `macos-13` in your build matrix to build `x86_64`. Check out the new [GitHub Actions example config](https://cibuildwheel.pypa.io/en/stable/setup/#github-actions).
|
||||||
- ✨ You no longer need to specify `--platform` to run cibuildwheel locally! Instead it will detect your platform automatically. This was a safety feature, no longer necessary. (#1727)
|
- ✨ You no longer need to specify `--platform` to run cibuildwheel locally! Instead it will detect your platform automatically. This was a safety feature, no longer necessary. (#1727)
|
||||||
- 🛠 Removed setuptools and wheel pinned versions. This only affects old-style projects without a `pyproject.toml`, projects with `pyproject.toml` are already getting fresh versions of their `build-system.requires` installed into an isolated environment. (#1725)
|
- 🛠 Removed setuptools and wheel pinned versions. This only affects old-style projects without a `pyproject.toml`, projects with `pyproject.toml` are already getting fresh versions of their `build-system.requires` installed into an isolated environment. (#1725)
|
||||||
- 🛠 Improve how the GitHub Action passes arguments (#1757)
|
- 🛠 Improve how the GitHub Action passes arguments (#1757)
|
||||||
- 🛠 Remove a system-wide install of pipx in the GitHub Action (#1745)
|
- 🛠 Remove a system-wide install of pipx in the GitHub Action (#1745)
|
||||||
- 🐛 No longer will cibuildwheel override the PIP_CONSTRAINT environment variable when using the `build` frontend. Instead it will be extended. (#1675)
|
- 🐛 No longer will cibuildwheel override the `PIP_CONSTRAINT` environment variable when using the `build` frontend. Instead it will be extended. (#1675)
|
||||||
- 🐛 Fix a bug where building and testing both x86_86 and arm64 wheels on the same runner caused the wrong architectures in the test environment (#1750)
|
- 🐛 Fix a bug where building and testing both `x86_86` and `arm64` wheels on the same runner caused the wrong architectures in the test environment (#1750)
|
||||||
- 🐛 Fix a bug that prevented testing a CPython 3.8 wheel targeting macOS 11+ on x86_64 (#1768)
|
- 🐛 Fix a bug that prevented testing a CPython 3.8 wheel targeting macOS 11+ on `x86_64` (#1768)
|
||||||
- 📚 Moved the docs onto the official PyPA domain - they're now available at https://cibuildwheel.pypa.io . (#1775)
|
- 📚 Moved the docs onto the official PyPA domain - they're now available at https://cibuildwheel.pypa.io . (#1775)
|
||||||
- 📚 Docs and examples improvements (#1762, #1734)
|
- 📚 Docs and examples improvements (#1762, #1734)
|
||||||
|
|
||||||
@@ -110,7 +172,7 @@ _10 July 2023_
|
|||||||
- 🛠 Updates the prerelease CPython 3.12 version to 3.12.0b3.
|
- 🛠 Updates the prerelease CPython 3.12 version to 3.12.0b3.
|
||||||
- ✨ Allow the use of the `{wheel}` placeholder in CIBW_TEST_COMMAND (#1533)
|
- ✨ Allow the use of the `{wheel}` placeholder in CIBW_TEST_COMMAND (#1533)
|
||||||
- 📚 Docs & examples updates (#1532, #1416)
|
- 📚 Docs & examples updates (#1532, #1416)
|
||||||
- ⚠️ Removed support for running cibuildwheel in Python 3.7. Python 3.7 is EOL. However, cibuildwheel continues to build Python 3.7 wheels for the moment. (#1175)
|
- ⚠️ Removed support for running cibuildwheel in Python 3.7. Python 3.7 is EOL. However, cibuildwheel continues to build Python 3.7 wheels for the moment. (#1175)
|
||||||
|
|
||||||
### v2.13.1
|
### v2.13.1
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ You can see a list of sessions by typing `nox -l`; here are a few common ones:
|
|||||||
```console
|
```console
|
||||||
nox -s lint # Run the linters (default)
|
nox -s lint # Run the linters (default)
|
||||||
nox -s tests [-- PYTEST-ARGS] # Run the tests (default)
|
nox -s tests [-- PYTEST-ARGS] # Run the tests (default)
|
||||||
nox -s docs -- serve # Build and serve the documentation
|
nox -s docs # Build and serve the documentation
|
||||||
nox -s build # Make SDist and wheel
|
nox -s build # Make SDist and wheel
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ Then, increment the project version number using:
|
|||||||
bin/bump_version.py
|
bin/bump_version.py
|
||||||
```
|
```
|
||||||
|
|
||||||
You'll be prompted to enter the new version number. Update the changelog when prompted. The script will create a 'bump version' commit and version tag.
|
(or `nox -s bump_version`) You'll be prompted to enter the new version number. Update the changelog when prompted. The script will create a 'bump version' commit and version tag.
|
||||||
|
|
||||||
Finally, cut the release and push to GitHub.
|
Finally, cut the release and push to GitHub.
|
||||||
|
|
||||||
@@ -186,3 +186,5 @@ git push && git push --tags
|
|||||||
```
|
```
|
||||||
|
|
||||||
Then head to https://github.com/pypa/cibuildwheel/releases and create a GitHub release from the new tag, pasting in the changelog entry. Once the release is created inside GitHub, a CI job will create the assets and upload them to PyPI.
|
Then head to https://github.com/pypa/cibuildwheel/releases and create a GitHub release from the new tag, pasting in the changelog entry. Once the release is created inside GitHub, a CI job will create the assets and upload them to PyPI.
|
||||||
|
|
||||||
|
If there were any schema updates, run `pipx run ./bin/generate_schema.py --schemastore > partial-cibuildwheel.json` and contribute the changes to SchemaStore.
|
||||||
|
|||||||
+14
-7
@@ -26,7 +26,7 @@
|
|||||||
notes: A simple C extension, without external dependencies
|
notes: A simple C extension, without external dependencies
|
||||||
|
|
||||||
- name: websockets
|
- name: websockets
|
||||||
gh: aaugustin/websockets
|
gh: python-websockets/websockets
|
||||||
ci: [travisci]
|
ci: [travisci]
|
||||||
ci_config: .travis.yml
|
ci_config: .travis.yml
|
||||||
os: [apple, linux]
|
os: [apple, linux]
|
||||||
@@ -325,12 +325,12 @@
|
|||||||
notes: Full range of wheels for setuptools rust, with auto release and PyPI deploy.
|
notes: Full range of wheels for setuptools rust, with auto release and PyPI deploy.
|
||||||
|
|
||||||
- name: python-snappy
|
- name: python-snappy
|
||||||
gh: andrix/python-snappy
|
gh: intake/python-snappy
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [apple, linux, windows]
|
os: [apple, linux, windows]
|
||||||
|
|
||||||
- name: sourmash
|
- name: sourmash
|
||||||
gh: dib-lab/sourmash
|
gh: sourmash-bio/sourmash
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [apple, linux, windows]
|
os: [apple, linux, windows]
|
||||||
|
|
||||||
@@ -418,7 +418,7 @@
|
|||||||
notes: Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension.
|
notes: Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension.
|
||||||
|
|
||||||
- name: pytorch-fairseq
|
- name: pytorch-fairseq
|
||||||
gh: pytorch/fairseq
|
gh: facebookresearch/fairseq
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [apple, linux]
|
os: [apple, linux]
|
||||||
|
|
||||||
@@ -475,7 +475,7 @@
|
|||||||
os: [apple, linux, windows]
|
os: [apple, linux, windows]
|
||||||
|
|
||||||
- name: OpenSpiel
|
- name: OpenSpiel
|
||||||
gh: deepmind/open_spiel
|
gh: google-deepmind/open_spiel
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [apple, linux]
|
os: [apple, linux]
|
||||||
|
|
||||||
@@ -505,7 +505,7 @@
|
|||||||
os: [apple, linux, windows]
|
os: [apple, linux, windows]
|
||||||
|
|
||||||
- name: OpenTimelineIO
|
- name: OpenTimelineIO
|
||||||
gh: PixarAnimationStudios/OpenTimelineIO
|
gh: AcademySoftwareFoundation/OpenTimelineIO
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [apple, linux, windows]
|
os: [apple, linux, windows]
|
||||||
|
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
notes: Includes GPU support for linux wheels
|
notes: Includes GPU support for linux wheels
|
||||||
|
|
||||||
- name: power-grid-model
|
- name: power-grid-model
|
||||||
gh: alliander-opensource/power-grid-model
|
gh: PowerGridModel/power-grid-model
|
||||||
ci: [github]
|
ci: [github]
|
||||||
os: [windows, apple, linux]
|
os: [windows, apple, linux]
|
||||||
notes: Python/C++ library for distribution power system analysis
|
notes: Python/C++ library for distribution power system analysis
|
||||||
@@ -657,3 +657,10 @@
|
|||||||
C++ framework. Uses cibuildwheel to deploy on as many operating
|
C++ framework. Uses cibuildwheel to deploy on as many operating
|
||||||
systems and Python versions as possible with only one dependency
|
systems and Python versions as possible with only one dependency
|
||||||
(any NumPy).
|
(any NumPy).
|
||||||
|
|
||||||
|
- name: streaming-form-data
|
||||||
|
gh: siddhantgoel/streaming-form-data
|
||||||
|
ci: [github]
|
||||||
|
os: [apple, linux, windows]
|
||||||
|
pypi: streaming-form-data
|
||||||
|
notes: Streaming parser for multipart/form-data written in Cython
|
||||||
|
|||||||
+20
-11
@@ -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:
|
If you use GitHub Actions for builds, you can use cibuildwheel as an action:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
uses: pypa/cibuildwheel@v2.18.0
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
```
|
```
|
||||||
|
|
||||||
This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal.
|
This is a composite step that just runs cibuildwheel using pipx. You can set command-line options as `with:` parameters, and use `env:` as normal.
|
||||||
@@ -164,7 +164,7 @@ The second option, and the only one that supports other CI systems, is using a `
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# requirements-cibw.txt
|
# requirements-cibw.txt
|
||||||
cibuildwheel==2.18.0
|
cibuildwheel==2.20.0
|
||||||
```
|
```
|
||||||
|
|
||||||
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this:
|
Then your install step would have `python -m pip install -r requirements-cibw.txt` in it. Your `.github/dependabot.yml` file could look like this:
|
||||||
@@ -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
|
# most runners have pipx preinstalled, but in case you don't
|
||||||
python3 -m pip install pipx
|
python3 -m pip install pipx
|
||||||
|
|
||||||
pipx run cibuildwheel==2.18.0 --output-dir wheelhouse
|
pipx run cibuildwheel==2.20.0 --output-dir wheelhouse
|
||||||
pipx run twine upload wheelhouse/*.whl
|
pipx run twine upload wheelhouse/*.whl
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -363,16 +363,25 @@ If you're building on an arm64 runner, you might notice something strange about
|
|||||||
|
|
||||||
This is fine for simple C extensions, but for more complicated builds on arm64 it becomes an issue.
|
This is fine for simple C extensions, but for more complicated builds on arm64 it becomes an issue.
|
||||||
|
|
||||||
So, if the cross-compilation is an issue for you, there is an 'experimental' installer available that's built natively for arm64.
|
So, if you want to build macOS arm64 wheels on an arm64 runner (e.g., `macos-14`) on Python 3.8, before invoking cibuildwheel, you should install a native arm64 Python 3.8 interpreter on the runner:
|
||||||
|
|
||||||
To use this installer and perform native CPython 3.8 building, before invoking cibuildwheel, install the universal2 version of Python on your arm64 runner, something like:
|
|
||||||
|
|
||||||
|
|
||||||
```bash
|
!!! tab "GitHub Actions"
|
||||||
curl -o /tmp/Python38.pkg https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg
|
|
||||||
sudo installer -pkg /tmp/Python38.pkg -target /
|
```yaml
|
||||||
sh "/Applications/Python 3.8/Install Certificates.command"
|
- uses: actions/setup-python@v5
|
||||||
```
|
with:
|
||||||
|
python-version: 3.8
|
||||||
|
if: runner.os == 'macOS' && runner.arch == 'ARM64'
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tab "Generic"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -o /tmp/Python38.pkg https://www.python.org/ftp/python/3.8.10/python-3.8.10-macos11.pkg
|
||||||
|
sudo installer -pkg /tmp/Python38.pkg -target /
|
||||||
|
sh "/Applications/Python 3.8/Install Certificates.command"
|
||||||
|
```
|
||||||
|
|
||||||
Then cibuildwheel will detect that it's installed and use it instead. However, you probably don't want to build x86_64 wheels on this Python, unless you're happy with them only supporting macOS 11+.
|
Then cibuildwheel will detect that it's installed and use it instead. However, you probably don't want to build x86_64 wheels on this Python, unless you're happy with them only supporting macOS 11+.
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -1,10 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sysconfig
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
# Requires Python 3.7+
|
|
||||||
|
|
||||||
|
|
||||||
def define_env(env: Any) -> None:
|
def define_env(env: Any) -> None:
|
||||||
"Hook function for mkdocs-macros"
|
"Hook function for mkdocs-macros"
|
||||||
@@ -12,4 +12,7 @@ def define_env(env: Any) -> None:
|
|||||||
@env.macro
|
@env.macro
|
||||||
def subprocess_run(*args: str) -> str:
|
def subprocess_run(*args: str) -> str:
|
||||||
"Run a subprocess and return the stdout"
|
"Run a subprocess and return the stdout"
|
||||||
return subprocess.run(args, check=True, capture_output=True, text=True).stdout
|
env = os.environ.copy()
|
||||||
|
scripts = sysconfig.get_path("scripts")
|
||||||
|
env["PATH"] = f"{scripts}{os.pathsep}{env.get('PATH', '')}"
|
||||||
|
return subprocess.run(args, check=True, capture_output=True, text=True, env=env).stdout
|
||||||
|
|||||||
+161
-28
@@ -91,9 +91,9 @@ You can configure cibuildwheel with a config file, such as `pyproject.toml`.
|
|||||||
Options have the same names as the environment variable overrides, but are
|
Options have the same names as the environment variable overrides, but are
|
||||||
placed in `[tool.cibuildwheel]` and are lower case, with dashes, following
|
placed in `[tool.cibuildwheel]` and are lower case, with dashes, following
|
||||||
common [TOML][] practice. Anything placed in subsections `linux`, `windows`,
|
common [TOML][] practice. Anything placed in subsections `linux`, `windows`,
|
||||||
or `macos` will only affect those platforms. Lists can be used instead of
|
`macos`, or `pyodide` will only affect those platforms. Lists can be used
|
||||||
strings for items that are naturally a list. Multiline strings also work just
|
instead of strings for items that are naturally a list. Multiline strings also
|
||||||
like in the environment variables. Environment variables will take
|
work just like in the environment variables. Environment variables will take
|
||||||
precedence if defined.
|
precedence if defined.
|
||||||
|
|
||||||
The example above using environment variables could have been written like this:
|
The example above using environment variables could have been written like this:
|
||||||
@@ -247,7 +247,7 @@ environment variables will completely override any TOML configuration.
|
|||||||
|
|
||||||
> Override the auto-detected target platform
|
> Override the auto-detected target platform
|
||||||
|
|
||||||
Options: `auto` `linux` `macos` `windows`
|
Options: `auto` `linux` `macos` `windows` `pyodide`
|
||||||
|
|
||||||
Default: `auto`
|
Default: `auto`
|
||||||
|
|
||||||
@@ -255,6 +255,7 @@ Default: `auto`
|
|||||||
|
|
||||||
- For `linux`, you need [Docker or Podman](#container-engine) running, on Linux, macOS, or Windows.
|
- For `linux`, you need [Docker or Podman](#container-engine) running, on Linux, macOS, or Windows.
|
||||||
- For `macos` and `windows`, you need to be running on the respective system, with a working compiler toolchain installed - Xcode Command Line tools for macOS, and MSVC for Windows.
|
- For `macos` and `windows`, you need to be running on the respective system, with a working compiler toolchain installed - Xcode Command Line tools for macOS, and MSVC for Windows.
|
||||||
|
- For `pyodide` you need to be on an x86-64 linux runner and `python3.12` must be available in `PATH`.
|
||||||
|
|
||||||
This option can also be set using the [command-line option](#command-line) `--platform`. This option is not available in the `pyproject.toml` config.
|
This option can also be set using the [command-line option](#command-line) `--platform`. This option is not available in the `pyproject.toml` config.
|
||||||
|
|
||||||
@@ -309,6 +310,9 @@ For CPython, the minimally supported macOS version is 10.9; for PyPy 3.7, macOS
|
|||||||
|
|
||||||
Windows arm64 platform support is experimental.
|
Windows arm64 platform support is experimental.
|
||||||
|
|
||||||
|
For an experimental WebAssembly build with `--platform pyodide`,
|
||||||
|
`cp312-pyodide_wasm32` is the only platform identifier.
|
||||||
|
|
||||||
See the [cibuildwheel 1 documentation](https://cibuildwheel.pypa.io/en/1.x/) for past end-of-life versions of Python, and PyPy2.7.
|
See the [cibuildwheel 1 documentation](https://cibuildwheel.pypa.io/en/1.x/) for past end-of-life versions of Python, and PyPy2.7.
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
@@ -408,6 +412,53 @@ See the [cibuildwheel 1 documentation](https://cibuildwheel.pypa.io/en/1.x/) for
|
|||||||
}
|
}
|
||||||
</style>
|
</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}
|
### `CIBW_ARCHS` {: #archs}
|
||||||
> Change the architectures built on your machine by default.
|
> Change the architectures built on your machine by default.
|
||||||
|
|
||||||
@@ -427,6 +478,7 @@ Options:
|
|||||||
- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x`
|
- Linux: `x86_64` `i686` `aarch64` `ppc64le` `s390x`
|
||||||
- macOS: `x86_64` `arm64` `universal2`
|
- macOS: `x86_64` `arm64` `universal2`
|
||||||
- Windows: `AMD64` `x86` `ARM64`
|
- Windows: `AMD64` `x86` `ARM64`
|
||||||
|
- Pyodide: `wasm32`
|
||||||
- `auto`: The default archs for your machine - see the table below.
|
- `auto`: The default archs for your machine - see the table below.
|
||||||
- `auto64`: Just the 64-bit auto archs
|
- `auto64`: Just the 64-bit auto archs
|
||||||
- `auto32`: Just the 32-bit auto archs
|
- `auto32`: Just the 32-bit auto archs
|
||||||
@@ -569,10 +621,32 @@ This option can also be set using the [command-line option](#command-line) `--pr
|
|||||||
CIBW_PRERELEASE_PYTHONS: True
|
CIBW_PRERELEASE_PYTHONS: True
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `CIBW_ALLOW_EMPTY` {: #allow-empty}
|
||||||
|
> Suppress the error code if no wheels match the specified build identifiers
|
||||||
|
|
||||||
|
When none of the specified build identifiers match any available versions,
|
||||||
|
cibuildwheel will typically return error code 3, indicating that there are
|
||||||
|
no wheels to build. Enabling this option will suppress this error, allowing
|
||||||
|
the build process to complete without signaling an error.
|
||||||
|
|
||||||
|
Default: Off (0). Error code 3 is returned when no builds are selected.
|
||||||
|
|
||||||
|
This option can also be set using the [command-line option](#command-line)
|
||||||
|
`--allow-empty`. This option is not available in the `pyproject.toml` config.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
!!! tab examples "Environment variables"
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Prevent an error code if the build does not match any wheels
|
||||||
|
CIBW_ALLOW_EMPTY: True
|
||||||
|
```
|
||||||
|
|
||||||
## Build customization
|
## Build customization
|
||||||
|
|
||||||
### `CIBW_BUILD_FRONTEND` {: #build-frontend}
|
### `CIBW_BUILD_FRONTEND` {: #build-frontend}
|
||||||
> Set the tool to use to build, either "pip" (default for now) or "build"
|
> Set the tool to use to build, either "pip" (default for now), "build", or "build\[uv\]"
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
@@ -584,17 +658,36 @@ Default: `pip`
|
|||||||
Choose which build frontend to use. Can either be "pip", which will run
|
Choose which build frontend to use. Can either be "pip", which will run
|
||||||
`python -m pip wheel`, or "build", which will run `python -m build --wheel`.
|
`python -m pip wheel`, or "build", which will run `python -m build --wheel`.
|
||||||
|
|
||||||
|
You can also use "build\[uv\]", which will use an external [uv][] everywhere
|
||||||
|
possible, both through `--installer=uv` passed to build, as well as when making
|
||||||
|
all build and test environments. This will generally speed up cibuildwheel.
|
||||||
|
Make sure you have an external uv on Windows and macOS, either by
|
||||||
|
pre-installing it, or installing cibuildwheel with the uv extra,
|
||||||
|
`cibuildwheel[uv]`. `uv` will not be used for Python 3.6 or Python 3.7. You
|
||||||
|
cannot use uv currently on Windows for ARM or for musllinux on s390x as
|
||||||
|
binaries are not provided by uv. Legacy dependencies like setuptools on Python
|
||||||
|
< 3.12 and pip are not installed if using uv.
|
||||||
|
|
||||||
|
Pyodide ignores this setting, as only "build" is supported.
|
||||||
|
|
||||||
You can specify extra arguments to pass to `pip wheel` or `build` using the
|
You can specify extra arguments to pass to `pip wheel` or `build` using the
|
||||||
optional `args` option.
|
optional `args` option.
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
Until v2.0.0, [pip] was the only way to build wheels, and is still the
|
Until v2.0.0, [pip][] was the only way to build wheels, and is still the
|
||||||
default. However, we expect that at some point in the future, cibuildwheel
|
default. However, we expect that at some point in the future, cibuildwheel
|
||||||
will change the default to [build], in line with the PyPA's recommendation.
|
will change the default to [build][], in line with the PyPA's recommendation.
|
||||||
If you want to try `build` before this, you can use this option.
|
If you want to try `build` before this, you can use this option.
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
If you are using `build[uv]` and are passing `--no-isolation` or `-n`, we
|
||||||
|
will detect this and avoid passing `--installer=uv` to build, but still
|
||||||
|
install all packages with uv. We do not currently detect combined short
|
||||||
|
options, like `-xn`!
|
||||||
|
|
||||||
[pip]: https://pip.pypa.io/en/stable/cli/pip_wheel/
|
[pip]: https://pip.pypa.io/en/stable/cli/pip_wheel/
|
||||||
[build]: https://github.com/pypa/build/
|
[build]: https://github.com/pypa/build/
|
||||||
|
[uv]: https://github.com/astral-sh/uv
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -609,6 +702,12 @@ optional `args` option.
|
|||||||
|
|
||||||
# supply an extra argument to 'pip wheel'
|
# supply an extra argument to 'pip wheel'
|
||||||
CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation"
|
CIBW_BUILD_FRONTEND: "pip; args: --no-build-isolation"
|
||||||
|
|
||||||
|
# Use uv and build
|
||||||
|
CIBW_BUILD_FRONTEND: "build[uv]"
|
||||||
|
|
||||||
|
# Use uv and build with an argument
|
||||||
|
CIBW_BUILD_FRONTEND: "build[uv]; args: --no-isolation"
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! tab examples "pyproject.toml"
|
!!! tab examples "pyproject.toml"
|
||||||
@@ -623,6 +722,12 @@ optional `args` option.
|
|||||||
|
|
||||||
# supply an extra argument to 'pip wheel'
|
# supply an extra argument to 'pip wheel'
|
||||||
build-frontend = { name = "pip", args = ["--no-build-isolation"] }
|
build-frontend = { name = "pip", args = ["--no-build-isolation"] }
|
||||||
|
|
||||||
|
# Use uv and build
|
||||||
|
build-frontend = "build[uv]"
|
||||||
|
|
||||||
|
# Use uv and build with an argument
|
||||||
|
build-frontend = { name = "build[uv]", args = ["--no-isolation"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
### `CIBW_CONFIG_SETTINGS` {: #config-settings}
|
### `CIBW_CONFIG_SETTINGS` {: #config-settings}
|
||||||
@@ -637,7 +742,7 @@ a table of items, including arrays.
|
|||||||
single values.
|
single values.
|
||||||
|
|
||||||
Platform-specific environment variables also available:<br/>
|
Platform-specific environment variables also available:<br/>
|
||||||
`CIBW_CONFIG_SETTINGS_MACOS` | `CIBW_CONFIG_SETTINGS_WINDOWS` | `CIBW_CONFIG_SETTINGS_LINUX`
|
`CIBW_CONFIG_SETTINGS_MACOS` | `CIBW_CONFIG_SETTINGS_WINDOWS` | `CIBW_CONFIG_SETTINGS_LINUX` | `CIBW_CONFIG_SETTINGS_PYODIDE`
|
||||||
|
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
@@ -668,7 +773,7 @@ You can use `$PATH` syntax to insert other variables, or the `$(pwd)` syntax to
|
|||||||
To specify more than one environment variable, separate the assignments by spaces.
|
To specify more than one environment variable, separate the assignments by spaces.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_ENVIRONMENT_MACOS` | `CIBW_ENVIRONMENT_WINDOWS` | `CIBW_ENVIRONMENT_LINUX`
|
`CIBW_ENVIRONMENT_MACOS` | `CIBW_ENVIRONMENT_WINDOWS` | `CIBW_ENVIRONMENT_LINUX` | `CIBW_ENVIRONMENT_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -741,7 +846,7 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
In configuration mode, you can use a [TOML][] table instead of a raw string as shown above.
|
In configuration mode, you can use a [TOML][] table instead of a raw string as shown above.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
cibuildwheel always defines the environment variable `CIBUILDWHEEL=1`. This can be useful for [building wheels with optional extensions](faq.md#building-packages-with-optional-c-extensions).
|
cibuildwheel always defines the environment variable `CIBUILDWHEEL=1`. This can be useful for [building wheels with optional extensions](faq.md#optional-extensions).
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
To do its work, cibuildwheel sets the variables `VIRTUALENV_PIP`, `DIST_EXTRA_CONFIG`, `SETUPTOOLS_EXT_SUFFIX`, `PIP_DISABLE_PIP_VERSION_CHECK`, `PIP_ROOT_USER_ACTION`, and it extends the variables `PATH` and `PIP_CONSTRAINT`. Your assignments to these options might be replaced or extended.
|
To do its work, cibuildwheel sets the variables `VIRTUALENV_PIP`, `DIST_EXTRA_CONFIG`, `SETUPTOOLS_EXT_SUFFIX`, `PIP_DISABLE_PIP_VERSION_CHECK`, `PIP_ROOT_USER_ACTION`, and it extends the variables `PATH` and `PIP_CONSTRAINT`. Your assignments to these options might be replaced or extended.
|
||||||
@@ -800,7 +905,7 @@ On linux, overriding it triggers a new container launch. It cannot be overridden
|
|||||||
on macOS and Windows.
|
on macOS and Windows.
|
||||||
|
|
||||||
Platform-specific environment variables also available:<br/>
|
Platform-specific environment variables also available:<br/>
|
||||||
`CIBW_BEFORE_ALL_MACOS` | `CIBW_BEFORE_ALL_WINDOWS` | `CIBW_BEFORE_ALL_LINUX`
|
`CIBW_BEFORE_ALL_MACOS` | `CIBW_BEFORE_ALL_WINDOWS` | `CIBW_BEFORE_ALL_LINUX` | `CIBW_BEFORE_ALL_PYODIDE`
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|
||||||
@@ -865,7 +970,7 @@ The active Python binary can be accessed using `python`, and pip with `pip`; cib
|
|||||||
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX`
|
`CIBW_BEFORE_BUILD_MACOS` | `CIBW_BEFORE_BUILD_WINDOWS` | `CIBW_BEFORE_BUILD_LINUX` | `CIBW_BEFORE_BUILD_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -946,6 +1051,7 @@ Default:
|
|||||||
- on Linux: `'auditwheel repair -w {dest_dir} {wheel}'`
|
- on Linux: `'auditwheel repair -w {dest_dir} {wheel}'`
|
||||||
- on macOS: `'delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}'`
|
- on macOS: `'delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}'`
|
||||||
- on Windows: `''`
|
- on Windows: `''`
|
||||||
|
- on Pyodide: `''`
|
||||||
|
|
||||||
A shell command to repair a built wheel by copying external library dependencies into the wheel tree and relinking them.
|
A shell command to repair a built wheel by copying external library dependencies into the wheel tree and relinking them.
|
||||||
The command is run on each built wheel (except for pure Python ones) before testing it.
|
The command is run on each built wheel (except for pure Python ones) before testing it.
|
||||||
@@ -959,7 +1065,7 @@ The following placeholders must be used inside the command and will be replaced
|
|||||||
The command is run in a shell, so you can run multiple commands like `cmd1 && cmd2`.
|
The command is run in a shell, so you can run multiple commands like `cmd1 && cmd2`.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_REPAIR_WHEEL_COMMAND_MACOS` | `CIBW_REPAIR_WHEEL_COMMAND_WINDOWS` | `CIBW_REPAIR_WHEEL_COMMAND_LINUX`
|
`CIBW_REPAIR_WHEEL_COMMAND_MACOS` | `CIBW_REPAIR_WHEEL_COMMAND_WINDOWS` | `CIBW_REPAIR_WHEEL_COMMAND_LINUX` | `CIBW_REPAIR_WHEEL_COMMAND_PYODIDE`
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
cibuildwheel doesn't yet ship a default repair command for Windows.
|
cibuildwheel doesn't yet ship a default repair command for Windows.
|
||||||
@@ -970,6 +1076,12 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
|
|
||||||
[Delvewheel]: https://github.com/adang1345/delvewheel
|
[Delvewheel]: https://github.com/adang1345/delvewheel
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
When using `--platform pyodide`, `pyodide build` is used to do the build,
|
||||||
|
which already uses `auditwheel-emscripten` to repair the wheel, so the default
|
||||||
|
repair command is empty. If there is a way to do this in two steps in the future,
|
||||||
|
this could change.
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
!!! tab examples "Environment variables"
|
!!! tab examples "Environment variables"
|
||||||
@@ -1234,7 +1346,7 @@ here and it will be used instead.
|
|||||||
`./constraints.txt` if that's not found.
|
`./constraints.txt` if that's not found.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_DEPENDENCY_VERSIONS_MACOS` | `CIBW_DEPENDENCY_VERSIONS_WINDOWS`
|
`CIBW_DEPENDENCY_VERSIONS_MACOS` | `CIBW_DEPENDENCY_VERSIONS_WINDOWS` | `CIBW_DEPENDENCY_VERSIONS_PYODIDE`
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
This option does not affect the tools used on the Linux build - those versions
|
This option does not affect the tools used on the Linux build - those versions
|
||||||
@@ -1292,16 +1404,13 @@ not be installed after building.
|
|||||||
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX`
|
`CIBW_TEST_COMMAND_MACOS` | `CIBW_TEST_COMMAND_WINDOWS` | `CIBW_TEST_COMMAND_LINUX` | `CIBW_TEST_COMMAND_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
!!! tab examples "Environment variables"
|
!!! tab examples "Environment variables"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Run the project tests against the installed wheel using `nose`
|
|
||||||
CIBW_TEST_COMMAND: nosetests {project}/tests
|
|
||||||
|
|
||||||
# Run the package tests using `pytest`
|
# Run the package tests using `pytest`
|
||||||
CIBW_TEST_COMMAND: pytest {package}/tests
|
CIBW_TEST_COMMAND: pytest {package}/tests
|
||||||
|
|
||||||
@@ -1318,9 +1427,6 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[tool.cibuildwheel]
|
[tool.cibuildwheel]
|
||||||
# Run the project tests against the installed wheel using `nose`
|
|
||||||
test-command = "nosetests {project}/tests"
|
|
||||||
|
|
||||||
# Run the package tests using `pytest`
|
# Run the package tests using `pytest`
|
||||||
test-command = "pytest {package}/tests"
|
test-command = "pytest {package}/tests"
|
||||||
|
|
||||||
@@ -1355,7 +1461,7 @@ The active Python binary can be accessed using `python`, and pip with `pip`; cib
|
|||||||
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
The command is run in a shell, so you can write things like `cmd1 && cmd2`.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_BEFORE_TEST_MACOS` | `CIBW_BEFORE_TEST_WINDOWS` | `CIBW_BEFORE_TEST_LINUX`
|
`CIBW_BEFORE_TEST_MACOS` | `CIBW_BEFORE_TEST_WINDOWS` | `CIBW_BEFORE_TEST_LINUX` | `CIBW_BEFORE_TEST_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -1415,7 +1521,7 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
Space-separated list of dependencies required for running the tests.
|
Space-separated list of dependencies required for running the tests.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_TEST_REQUIRES_MACOS` | `CIBW_TEST_REQUIRES_WINDOWS` | `CIBW_TEST_REQUIRES_LINUX`
|
`CIBW_TEST_REQUIRES_MACOS` | `CIBW_TEST_REQUIRES_WINDOWS` | `CIBW_TEST_REQUIRES_LINUX` | `CIBW_TEST_REQUIRES_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -1426,7 +1532,7 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
CIBW_TEST_REQUIRES: pytest
|
CIBW_TEST_REQUIRES: pytest
|
||||||
|
|
||||||
# Install specific versions of test dependencies
|
# Install specific versions of test dependencies
|
||||||
CIBW_TEST_REQUIRES: nose==1.3.7 moto==0.4.31
|
CIBW_TEST_REQUIRES: pytest==8.2.2 packaging==24.1
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! tab examples "pyproject.toml"
|
!!! tab examples "pyproject.toml"
|
||||||
@@ -1438,7 +1544,7 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
|
|
||||||
# Install specific versions of test dependencies
|
# Install specific versions of test dependencies
|
||||||
[tool.cibuildwheel]
|
[tool.cibuildwheel]
|
||||||
test-requires = ["nose==1.3.7", "moto==0.4.31"]
|
test-requires = ["pytest==8.2.2", "packaging==24.1"]
|
||||||
```
|
```
|
||||||
|
|
||||||
In configuration files, you can use an array, and the items will be joined with a space.
|
In configuration files, you can use an array, and the items will be joined with a space.
|
||||||
@@ -1455,7 +1561,7 @@ tests. This can be used to avoid having to redefine test dependencies in
|
|||||||
`setup.cfg` or `setup.py`.
|
`setup.cfg` or `setup.py`.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_TEST_EXTRAS_MACOS` | `CIBW_TEST_EXTRAS_WINDOWS` | `CIBW_TEST_EXTRAS_LINUX`
|
`CIBW_TEST_EXTRAS_MACOS` | `CIBW_TEST_EXTRAS_WINDOWS` | `CIBW_TEST_EXTRAS_LINUX` | `CIBW_TEST_EXTRAS_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -1528,13 +1634,27 @@ Default: Off (0).
|
|||||||
export CIBW_DEBUG_KEEP_CONTAINER=TRUE
|
export CIBW_DEBUG_KEEP_CONTAINER=TRUE
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `CIBW_DEBUG_TRACEBACK`
|
||||||
|
> Print full traceback when errors occur.
|
||||||
|
|
||||||
|
Print a full traceback for the cibuildwheel process when errors occur. This
|
||||||
|
option is provided for debugging cibuildwheel.
|
||||||
|
|
||||||
|
This option can also be set using the [command-line option](#command-line) `--debug-traceback`.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
```shell
|
||||||
|
export CIBW_DEBUG_TRACEBACK=TRUE
|
||||||
|
```
|
||||||
|
|
||||||
### `CIBW_BUILD_VERBOSITY` {: #build-verbosity}
|
### `CIBW_BUILD_VERBOSITY` {: #build-verbosity}
|
||||||
> Increase/decrease the output of pip wheel
|
> Increase/decrease the output of pip wheel
|
||||||
|
|
||||||
A number from 1 to 3 to increase the level of verbosity (corresponding to invoking pip with `-v`, `-vv`, and `-vvv`), between -1 and -3 (`-q`, `-qq`, and `-qqq`), or just 0 (default verbosity). These flags are useful while debugging a build when the output of the actual build invoked by `pip wheel` is required. Has no effect on the `build` backend, which produces verbose output by default.
|
A number from 1 to 3 to increase the level of verbosity (corresponding to invoking pip with `-v`, `-vv`, and `-vvv`), between -1 and -3 (`-q`, `-qq`, and `-qqq`), or just 0 (default verbosity). These flags are useful while debugging a build when the output of the actual build invoked by `pip wheel` is required. Has no effect on the `build` backend, which produces verbose output by default.
|
||||||
|
|
||||||
Platform-specific environment variables are also available:<br/>
|
Platform-specific environment variables are also available:<br/>
|
||||||
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX`
|
`CIBW_BUILD_VERBOSITY_MACOS` | `CIBW_BUILD_VERBOSITY_WINDOWS` | `CIBW_BUILD_VERBOSITY_LINUX` | `CIBW_BUILD_VERBOSITY_PYODIDE`
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
@@ -1554,12 +1674,25 @@ Platform-specific environment variables are also available:<br/>
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Command line options {: #command-line}
|
## Command line {: #command-line}
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
```text
|
```text
|
||||||
« subprocess_run("cibuildwheel", "--help") »
|
« subprocess_run("cibuildwheel", "--help") »
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Return codes
|
||||||
|
|
||||||
|
cibuildwheel exits 0 on success, or >0 if an error occurs.
|
||||||
|
|
||||||
|
Specific error codes are defined:
|
||||||
|
|
||||||
|
- 2 means a configuration error
|
||||||
|
- 3 means no builds are selected (and [`--allow-empty`](#allow-empty) wasn't passed)
|
||||||
|
- 4 means you specified an option that has been deprecated.
|
||||||
|
|
||||||
|
|
||||||
## Placeholders
|
## Placeholders
|
||||||
|
|
||||||
Some options support placeholders, like `{project}`, `{package}` or `{wheel}`, that are substituted by cibuildwheel before they are used. If, for some reason, you need to write the literal name of a placeholder, e.g. literally `{project}` in a command that would ordinarily substitute `{project}`, prefix it with a hash character - `#{project}`. This is only necessary in commands where the specific string between the curly brackets would be substituted - otherwise, strings not modified.
|
Some options support placeholders, like `{project}`, `{package}` or `{wheel}`, that are substituted by cibuildwheel before they are used. If, for some reason, you need to write the literal name of a placeholder, e.g. literally `{project}` in a command that would ordinarily substitute `{project}`, prefix it with a hash character - `#{project}`. This is only necessary in commands where the specific string between the curly brackets would be substituted - otherwise, strings not modified.
|
||||||
|
|||||||
+9
-2
@@ -107,6 +107,13 @@ You can override the cache folder using the ``CIBW_CACHE_PATH`` environment vari
|
|||||||
Download link: https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg
|
Download link: https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pyodide (WebAssembly) builds (experimental)
|
||||||
|
|
||||||
|
Pre-requisite: you need to have a matching host version of Python (unlike all
|
||||||
|
other cibuildwheel platforms). Linux host highly recommended; macOS hosts may
|
||||||
|
work (e.g. invoking `pytest` directly in [`CIBW_TEST_COMMAND`](options.md#test-command) is [currently failing](https://github.com/pyodide/pyodide/issues/4802)) and Windows hosts will not work.
|
||||||
|
|
||||||
|
You must target pyodide with `--platform pyodide` (or use `--only` on the identifier).
|
||||||
|
|
||||||
## Configure a CI service
|
## Configure a CI service
|
||||||
|
|
||||||
@@ -154,7 +161,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
run: pipx run cibuildwheel==2.18.0
|
run: pipx run cibuildwheel==2.20.0
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -191,7 +198,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
|
|||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
|
|
||||||
- name: Install cibuildwheel
|
- name: Install cibuildwheel
|
||||||
run: python -m pip install cibuildwheel==2.18.0
|
run: python -m pip install cibuildwheel==2.20.0
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
run: python -m cibuildwheel --output-dir wheelhouse
|
run: python -m cibuildwheel --output-dir wheelhouse
|
||||||
|
|||||||
+38
-36
@@ -11,13 +11,13 @@ title: Working examples
|
|||||||
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
||||||
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
||||||
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
||||||
|
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
|
||||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||||
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
|
||||||
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
||||||
|
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
||||||
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
||||||
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
|
| [MyPy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | The compiled version of MyPy using MyPyC. |
|
||||||
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
|
| [Kivy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Open source UI framework written in Python, running on Windows, Linux, macOS, Android and iOS |
|
||||||
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an in-process SQL OLAP Database Management System |
|
|
||||||
| [MemRay][] | ![github icon][] | ![linux icon][] | Memray is a memory profiler for Python |
|
| [MemRay][] | ![github icon][] | ![linux icon][] | Memray is a memory profiler for Python |
|
||||||
| [Triton][] | ![github icon][] | ![linux icon][] | Self hosted runners |
|
| [Triton][] | ![github icon][] | ![linux icon][] | Self hosted runners |
|
||||||
| [uvloop][] | ![github icon][] | ![apple icon][] ![linux icon][] | Ultra fast asyncio event loop. |
|
| [uvloop][] | ![github icon][] | ![apple icon][] ![linux icon][] | Ultra fast asyncio event loop. |
|
||||||
@@ -38,14 +38,13 @@ title: Working examples
|
|||||||
| [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings |
|
| [UltraJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Ultra fast JSON decoder and encoder written in C with Python bindings |
|
||||||
| [OpenSpiel][] | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. |
|
| [OpenSpiel][] | ![github icon][] | ![apple icon][] ![linux icon][] | OpenSpiel is a collection of environments and algorithms for research in general reinforcement learning and search/planning in games. |
|
||||||
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
|
| [aiortc][] | ![github icon][] | ![apple icon][] ![linux icon][] | WebRTC and ORTC implementation for Python using asyncio. |
|
||||||
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
|
|
||||||
| [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI |
|
| [Dependency Injector][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Dependency injection framework for Python, uses Windows TravisCI |
|
||||||
| [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. |
|
| [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 |
|
| [Implicit][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes GPU support for linux wheels |
|
||||||
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
|
| [vispy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Main repository for Vispy |
|
||||||
| [tinyobjloader][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader |
|
| [tinyobjloader][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Tiny but powerful single file wavefront obj loader |
|
||||||
| [coverage.py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The coverage tool for Python |
|
|
||||||
| [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. |
|
| [CTranslate2][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes libraries from the [Intel oneAPI toolkit](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html) and CUDA kernels compiled for multiple GPU architectures. |
|
||||||
|
| [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 |
|
| [PyCryptodome][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A self-contained cryptographic library for Python |
|
||||||
| [Line Profiler][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Line-by-line profiling for Python |
|
| [Line Profiler][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Line-by-line profiling for Python |
|
||||||
| [PyYAML][] | ![github icon][] | ![apple icon][] | Canonical source repository for PyYAML |
|
| [PyYAML][] | ![github icon][] | ![apple icon][] | Canonical source repository for PyYAML |
|
||||||
@@ -56,31 +55,31 @@ title: Working examples
|
|||||||
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
|
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
|
||||||
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
|
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
|
||||||
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
|
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
|
||||||
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
|
|
||||||
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
|
|
||||||
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
|
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
|
||||||
|
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
|
||||||
|
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
|
||||||
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
|
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
|
||||||
| [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. |
|
| [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. |
|
||||||
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
|
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
|
||||||
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
|
|
||||||
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
|
| [google neuroglancer][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | WebGL-based viewer for volumetric data |
|
||||||
|
| [Parselmouth][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python interface to the Praat software package, using pybind11, C++17 and CMake, with the core Praat static library built only once and shared between wheels. |
|
||||||
| [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
|
| [DeepForest][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | An Efficient, Scalable and Optimized Python Framework for Deep Forest (2021.2.1) |
|
||||||
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
| [AutoPy][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
||||||
| [H3-py][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
|
| [H3-py][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for H3, a hierarchical hexagonal geospatial indexing system |
|
||||||
| [mosec][] | ![github icon][] | ![linux icon][] ![apple icon][] | A machine learning model serving framework powered by Rust |
|
| [mosec][] | ![github icon][] | ![linux icon][] ![apple icon][] | A machine learning model serving framework powered by Rust |
|
||||||
| [Picologging][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A high-performance logging library for Python. |
|
|
||||||
| [time-machine][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Time mocking library using only the CPython C API. |
|
| [time-machine][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Time mocking library using only the CPython C API. |
|
||||||
|
| [Picologging][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A high-performance logging library for Python. |
|
||||||
| [markupsafe][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. |
|
| [markupsafe][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Safely add untrusted strings to HTML/XML markup. |
|
||||||
| [Rtree][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Rtree: spatial index for Python GIS |
|
| [Rtree][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Rtree: spatial index for Python GIS |
|
||||||
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
|
| [pybind11 cmake_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a CMake-based build system |
|
||||||
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
|
| [KDEpy][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Kernel Density Estimation in Python |
|
||||||
| [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub |
|
| [dd-trace-py][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Uses custom alternate arch emulation on GitHub |
|
||||||
| [python-rapidjson][] | ![travisci icon][] ![gitlab icon][] ![appveyor icon][] | ![windows icon][] ![linux icon][] | Python wrapper around rapidjson |
|
|
||||||
| [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. |
|
| [tgcalls][] | ![github icon][] | ![apple icon][] ![windows icon][] | Python `pybind11` binding to Telegram's WebRTC library with third party dependencies like `OpenSSL`, `MozJPEG`, `FFmpeg`, etc. |
|
||||||
| [python-snappy][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Python bindings for the snappy google library |
|
| [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 |
|
| [pybind11 python_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Example pybind11 module built with a Python-based build system |
|
||||||
| [sourmash][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Quickly search, compare, and analyze genomic and metagenomic data sets. |
|
| [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. |
|
| [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. |
|
||||||
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
|
| [cyvcf2][] | ![github icon][] | ![apple icon][] ![linux icon][] | cython + htslib == fast VCF and BCF processing |
|
||||||
| [matrixprofile][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python 3 library making time series data mining tasks, utilizing matrix profile algorithms, accessible to everyone. |
|
| [matrixprofile][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python 3 library making time series data mining tasks, utilizing matrix profile algorithms, accessible to everyone. |
|
||||||
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
|
| [jq.py][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | Python bindings for jq |
|
||||||
@@ -91,42 +90,44 @@ title: Working examples
|
|||||||
| [pillow-heif][] | ![github icon][] ![cirrusci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Bindings to libheif library with third party dependencies. Fully automated CI for tests and publishing including Apple Silicon builds. |
|
| [pillow-heif][] | ![github icon][] ![cirrusci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Bindings to libheif library with third party dependencies. Fully automated CI for tests and publishing including Apple Silicon builds. |
|
||||||
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
| [TgCrypto][] | ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Includes a Windows Travis build. |
|
||||||
| [iDynTree][] | ![github icon][] | ![linux icon][] | Uses manylinux_2_24 |
|
| [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. |
|
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
|
||||||
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
|
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
|
||||||
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
|
|
||||||
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
|
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
|
||||||
|
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
|
||||||
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
|
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
|
||||||
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
|
|
||||||
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
|
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
|
||||||
|
| [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. |
|
| [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 |
|
| [pybind11 scikit_build_example][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | An example combining scikit-build and pybind11 |
|
||||||
| [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. |
|
| [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. |
|
||||||
| [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. |
|
| [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. |
|
||||||
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
|
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
|
||||||
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
|
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
|
||||||
|
| [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. |
|
| [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 |
|
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
|
||||||
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
|
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
|
||||||
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
|
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
|
||||||
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
|
|
||||||
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
|
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
|
||||||
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
|
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
|
||||||
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
|
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
|
||||||
|
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
|
||||||
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
|
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
|
||||||
| [pyinstrument_cext][] | ![travisci icon][] ![appveyor icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A simple C extension, without external dependencies |
|
|
||||||
| [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). |
|
| [werpy][] | ![github icon][] | ![windows icon][] ![linux icon][] ![apple icon][] | An ultra-fast python package using optimized dynamic programming to compute the Word Error Rate (WER). |
|
||||||
|
| [pyinstrument_cext][] | ![travisci icon][] ![appveyor icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A simple C extension, without external dependencies |
|
||||||
| [pybind11 cross build example][] | ![github icon][] ![gitlab icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Same as pybind11 cmake_example but used to demo Linux ARM + Windows + macOS builds on GitLab |
|
| [pybind11 cross build example][] | ![github icon][] ![gitlab icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Same as pybind11 cmake_example but used to demo Linux ARM + Windows + macOS builds on GitLab |
|
||||||
|
|
||||||
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
||||||
[pytorch-fairseq]: https://github.com/pytorch/fairseq
|
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
|
||||||
[NumPy]: https://github.com/numpy/numpy
|
[NumPy]: https://github.com/numpy/numpy
|
||||||
|
[duckdb]: https://github.com/duckdb/duckdb
|
||||||
[Tornado]: https://github.com/tornadoweb/tornado
|
[Tornado]: https://github.com/tornadoweb/tornado
|
||||||
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
|
||||||
[NCNN]: https://github.com/Tencent/ncnn
|
[NCNN]: https://github.com/Tencent/ncnn
|
||||||
|
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
||||||
[Prophet]: https://github.com/facebook/prophet
|
[Prophet]: https://github.com/facebook/prophet
|
||||||
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
|
[MyPy]: https://github.com/mypyc/mypy_mypyc-wheels
|
||||||
[Kivy]: https://github.com/kivy/kivy
|
[Kivy]: https://github.com/kivy/kivy
|
||||||
[duckdb]: https://github.com/duckdb/duckdb
|
|
||||||
[MemRay]: https://github.com/bloomberg/memray
|
[MemRay]: https://github.com/bloomberg/memray
|
||||||
[Triton]: https://github.com/openai/triton
|
[Triton]: https://github.com/openai/triton
|
||||||
[uvloop]: https://github.com/MagicStack/uvloop
|
[uvloop]: https://github.com/MagicStack/uvloop
|
||||||
@@ -141,20 +142,19 @@ title: Working examples
|
|||||||
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
|
[twisted-iocpsupport]: https://github.com/twisted/twisted-iocpsupport
|
||||||
[PyOxidizer]: https://github.com/indygreg/PyOxidizer
|
[PyOxidizer]: https://github.com/indygreg/PyOxidizer
|
||||||
[cvxpy]: https://github.com/cvxpy/cvxpy
|
[cvxpy]: https://github.com/cvxpy/cvxpy
|
||||||
[websockets]: https://github.com/aaugustin/websockets
|
[websockets]: https://github.com/python-websockets/websockets
|
||||||
[pedalboard]: https://github.com/spotify/pedalboard
|
[pedalboard]: https://github.com/spotify/pedalboard
|
||||||
[River]: https://github.com/online-ml/river
|
[River]: https://github.com/online-ml/river
|
||||||
[UltraJSON]: https://github.com/ultrajson/ultrajson
|
[UltraJSON]: https://github.com/ultrajson/ultrajson
|
||||||
[OpenSpiel]: https://github.com/deepmind/open_spiel
|
[OpenSpiel]: https://github.com/google-deepmind/open_spiel
|
||||||
[aiortc]: https://github.com/aiortc/aiortc
|
[aiortc]: https://github.com/aiortc/aiortc
|
||||||
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
|
|
||||||
[Dependency Injector]: https://github.com/ets-labs/python-dependency-injector
|
[Dependency Injector]: https://github.com/ets-labs/python-dependency-injector
|
||||||
[pyzmq]: https://github.com/zeromq/pyzmq
|
[pyzmq]: https://github.com/zeromq/pyzmq
|
||||||
[Implicit]: https://github.com/benfred/implicit
|
[Implicit]: https://github.com/benfred/implicit
|
||||||
[vispy]: https://github.com/vispy/vispy
|
[vispy]: https://github.com/vispy/vispy
|
||||||
[tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
|
[tinyobjloader]: https://github.com/tinyobjloader/tinyobjloader
|
||||||
[coverage.py]: https://github.com/nedbat/coveragepy
|
|
||||||
[CTranslate2]: https://github.com/OpenNMT/CTranslate2
|
[CTranslate2]: https://github.com/OpenNMT/CTranslate2
|
||||||
|
[coverage.py]: https://github.com/nedbat/coveragepy
|
||||||
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
|
[PyCryptodome]: https://github.com/Legrandin/pycryptodome
|
||||||
[Line Profiler]: https://github.com/pyutils/line_profiler
|
[Line Profiler]: https://github.com/pyutils/line_profiler
|
||||||
[PyYAML]: https://github.com/yaml/pyyaml
|
[PyYAML]: https://github.com/yaml/pyyaml
|
||||||
@@ -165,31 +165,31 @@ title: Working examples
|
|||||||
[Wrapt]: https://github.com/GrahamDumpleton/wrapt
|
[Wrapt]: https://github.com/GrahamDumpleton/wrapt
|
||||||
[envd]: https://github.com/tensorchord/envd
|
[envd]: https://github.com/tensorchord/envd
|
||||||
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
|
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
|
||||||
[SimpleJSON]: https://github.com/simplejson/simplejson
|
|
||||||
[aioquic]: https://github.com/aiortc/aioquic
|
|
||||||
[Psycopg 3]: https://github.com/psycopg/psycopg
|
[Psycopg 3]: https://github.com/psycopg/psycopg
|
||||||
|
[aioquic]: https://github.com/aiortc/aioquic
|
||||||
|
[SimpleJSON]: https://github.com/simplejson/simplejson
|
||||||
[ruptures]: https://github.com/deepcharles/ruptures
|
[ruptures]: https://github.com/deepcharles/ruptures
|
||||||
[OpenTimelineIO]: https://github.com/PixarAnimationStudios/OpenTimelineIO
|
[OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO
|
||||||
[PyTables]: https://github.com/PyTables/PyTables
|
[PyTables]: https://github.com/PyTables/PyTables
|
||||||
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
|
|
||||||
[google neuroglancer]: https://github.com/google/neuroglancer
|
[google neuroglancer]: https://github.com/google/neuroglancer
|
||||||
|
[Parselmouth]: https://github.com/YannickJadoul/Parselmouth
|
||||||
[DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
|
[DeepForest]: https://github.com/LAMDA-NJU/Deep-Forest
|
||||||
[AutoPy]: https://github.com/autopilot-rs/autopy
|
[AutoPy]: https://github.com/autopilot-rs/autopy
|
||||||
[H3-py]: https://github.com/uber/h3-py
|
[H3-py]: https://github.com/uber/h3-py
|
||||||
[mosec]: https://github.com/mosecorg/mosec
|
[mosec]: https://github.com/mosecorg/mosec
|
||||||
[Picologging]: https://github.com/microsoft/picologging
|
|
||||||
[time-machine]: https://github.com/adamchainz/time-machine
|
[time-machine]: https://github.com/adamchainz/time-machine
|
||||||
|
[Picologging]: https://github.com/microsoft/picologging
|
||||||
[markupsafe]: https://github.com/pallets/markupsafe
|
[markupsafe]: https://github.com/pallets/markupsafe
|
||||||
[Rtree]: https://github.com/Toblerity/rtree
|
[Rtree]: https://github.com/Toblerity/rtree
|
||||||
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
|
[pybind11 cmake_example]: https://github.com/pybind/cmake_example
|
||||||
[KDEpy]: https://github.com/tommyod/KDEpy
|
[KDEpy]: https://github.com/tommyod/KDEpy
|
||||||
[dd-trace-py]: https://github.com/DataDog/dd-trace-py
|
[dd-trace-py]: https://github.com/DataDog/dd-trace-py
|
||||||
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
|
|
||||||
[tgcalls]: https://github.com/MarshalX/tgcalls
|
[tgcalls]: https://github.com/MarshalX/tgcalls
|
||||||
[python-snappy]: https://github.com/andrix/python-snappy
|
[python-rapidjson]: https://github.com/python-rapidjson/python-rapidjson
|
||||||
[pybind11 python_example]: https://github.com/pybind/python_example
|
[pybind11 python_example]: https://github.com/pybind/python_example
|
||||||
[sourmash]: https://github.com/dib-lab/sourmash
|
[python-snappy]: https://github.com/intake/python-snappy
|
||||||
[abess]: https://github.com/abess-team/abess
|
[abess]: https://github.com/abess-team/abess
|
||||||
|
[sourmash]: https://github.com/sourmash-bio/sourmash
|
||||||
[cyvcf2]: https://github.com/brentp/cyvcf2
|
[cyvcf2]: https://github.com/brentp/cyvcf2
|
||||||
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
|
[matrixprofile]: https://github.com/matrix-profile-foundation/matrixprofile
|
||||||
[jq.py]: https://github.com/mwilliamson/jq.py
|
[jq.py]: https://github.com/mwilliamson/jq.py
|
||||||
@@ -200,30 +200,32 @@ title: Working examples
|
|||||||
[pillow-heif]: https://github.com/bigcat88/pillow_heif
|
[pillow-heif]: https://github.com/bigcat88/pillow_heif
|
||||||
[TgCrypto]: https://github.com/pyrogram/tgcrypto
|
[TgCrypto]: https://github.com/pyrogram/tgcrypto
|
||||||
[iDynTree]: https://github.com/robotology/idyntree
|
[iDynTree]: https://github.com/robotology/idyntree
|
||||||
|
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
|
||||||
[bx-python]: https://github.com/bxlab/bx-python
|
[bx-python]: https://github.com/bxlab/bx-python
|
||||||
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
|
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
|
||||||
|
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
|
||||||
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
|
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
|
||||||
[power-grid-model]: https://github.com/alliander-opensource/power-grid-model
|
|
||||||
[pybase64]: https://github.com/mayeut/pybase64
|
[pybase64]: https://github.com/mayeut/pybase64
|
||||||
[fathon]: https://github.com/stfbnc/fathon
|
|
||||||
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
|
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
|
||||||
|
[fathon]: https://github.com/stfbnc/fathon
|
||||||
[Arbor]: https://github.com/arbor-sim/arbor
|
[Arbor]: https://github.com/arbor-sim/arbor
|
||||||
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
|
[pybind11 scikit_build_example]: https://github.com/pybind/scikit_build_example
|
||||||
[polaroid]: https://github.com/daggy1234/polaroid
|
[polaroid]: https://github.com/daggy1234/polaroid
|
||||||
[clang-format]: https://github.com/ssciwr/clang-format-wheel
|
[clang-format]: https://github.com/ssciwr/clang-format-wheel
|
||||||
[etebase-py]: https://github.com/etesync/etebase-py
|
[etebase-py]: https://github.com/etesync/etebase-py
|
||||||
[cf-units]: https://github.com/SciTools/cf-units
|
[cf-units]: https://github.com/SciTools/cf-units
|
||||||
|
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
|
||||||
[ninja]: https://github.com/scikit-build/ninja-python-distributions
|
[ninja]: https://github.com/scikit-build/ninja-python-distributions
|
||||||
[numpythia]: https://github.com/scikit-hep/numpythia
|
[numpythia]: https://github.com/scikit-hep/numpythia
|
||||||
[pyjet]: https://github.com/scikit-hep/pyjet
|
[pyjet]: https://github.com/scikit-hep/pyjet
|
||||||
[ril]: https://github.com/Cryptex-github/ril-py
|
[ril]: https://github.com/Cryptex-github/ril-py
|
||||||
[GSD]: https://github.com/glotzerlab/gsd
|
|
||||||
[SiPM]: https://github.com/EdoPro98/SimSiPM
|
[SiPM]: https://github.com/EdoPro98/SimSiPM
|
||||||
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
|
[GSD]: https://github.com/glotzerlab/gsd
|
||||||
[aalink]: https://github.com/artfwo/aalink
|
[aalink]: https://github.com/artfwo/aalink
|
||||||
|
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
|
||||||
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
|
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
|
||||||
[pyinstrument_cext]: https://github.com/joerick/pyinstrument_cext
|
|
||||||
[werpy]: https://github.com/analyticsinmotion/werpy
|
[werpy]: https://github.com/analyticsinmotion/werpy
|
||||||
|
[pyinstrument_cext]: https://github.com/joerick/pyinstrument_cext
|
||||||
[pybind11 cross build example]: https://github.com/wbarnha/pybind_cmake_example_crossbuild
|
[pybind11 cross build example]: https://github.com/wbarnha/pybind_cmake_example_crossbuild
|
||||||
|
|
||||||
[appveyor icon]: data/readme_icons/appveyor.svg
|
[appveyor icon]: data/readme_icons/appveyor.svg
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
|
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
|
||||||
APPVEYOR_JOB_NAME: "python37-x64-ubuntu"
|
APPVEYOR_JOB_NAME: "linux-x64"
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||||
APPVEYOR_JOB_NAME: "python37-x64-vs2015"
|
APPVEYOR_JOB_NAME: "windows-x64"
|
||||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos
|
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
|
||||||
APPVEYOR_JOB_NAME: "python37-x64-macos"
|
APPVEYOR_JOB_NAME: "macos-x64"
|
||||||
|
|
||||||
stack: python 3.7
|
stack: python 3.12
|
||||||
|
|
||||||
init:
|
install: python -m pip install cibuildwheel==2.20.0
|
||||||
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
|
|
||||||
|
|
||||||
install: python -m pip install cibuildwheel==2.18.0
|
|
||||||
|
|
||||||
build_script: python -m cibuildwheel --output-dir wheelhouse
|
build_script: python -m cibuildwheel --output-dir wheelhouse
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ jobs:
|
|||||||
- bash: |
|
- bash: |
|
||||||
set -o errexit
|
set -o errexit
|
||||||
python3 -m pip install --upgrade pip
|
python3 -m pip install --upgrade pip
|
||||||
pip3 install cibuildwheel==2.18.0
|
pip3 install cibuildwheel==2.20.0
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
- bash: cibuildwheel --output-dir wheelhouse .
|
- bash: cibuildwheel --output-dir wheelhouse .
|
||||||
displayName: Build wheels
|
displayName: Build wheels
|
||||||
@@ -14,13 +14,13 @@ jobs:
|
|||||||
inputs: {pathtoPublish: 'wheelhouse'}
|
inputs: {pathtoPublish: 'wheelhouse'}
|
||||||
|
|
||||||
- job: macos
|
- job: macos
|
||||||
pool: {vmImage: 'macOS-11'}
|
pool: {vmImage: 'macOS-12'}
|
||||||
steps:
|
steps:
|
||||||
- task: UsePythonVersion@0
|
- task: UsePythonVersion@0
|
||||||
- bash: |
|
- bash: |
|
||||||
set -o errexit
|
set -o errexit
|
||||||
python3 -m pip install --upgrade pip
|
python3 -m pip install --upgrade pip
|
||||||
python3 -m pip install cibuildwheel==2.18.0
|
python3 -m pip install cibuildwheel==2.20.0
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
- bash: cibuildwheel --output-dir wheelhouse .
|
- bash: cibuildwheel --output-dir wheelhouse .
|
||||||
displayName: Build wheels
|
displayName: Build wheels
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
- bash: |
|
- bash: |
|
||||||
set -o errexit
|
set -o errexit
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install cibuildwheel==2.18.0
|
pip install cibuildwheel==2.20.0
|
||||||
displayName: Install dependencies
|
displayName: Install dependencies
|
||||||
- bash: cibuildwheel --output-dir wheelhouse .
|
- bash: cibuildwheel --output-dir wheelhouse .
|
||||||
displayName: Build wheels
|
displayName: Build wheels
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ jobs:
|
|||||||
linux-wheels:
|
linux-wheels:
|
||||||
working_directory: ~/linux-wheels
|
working_directory: ~/linux-wheels
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/python:3.9
|
- image: cimg/python:3.12
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
- run:
|
- run:
|
||||||
name: Build the Linux wheels.
|
name: Build the Linux wheels.
|
||||||
command: |
|
command: |
|
||||||
pip3 install --user cibuildwheel==2.18.0
|
python3 -m pip install --user cibuildwheel==2.20.0
|
||||||
cibuildwheel --output-dir wheelhouse
|
cibuildwheel --output-dir wheelhouse
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: wheelhouse/
|
path: wheelhouse/
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Build the Linux aarch64 wheels.
|
name: Build the Linux aarch64 wheels.
|
||||||
command: |
|
command: |
|
||||||
python3 -m pip install --user cibuildwheel==2.18.0
|
python3 -m pip install --user cibuildwheel==2.20.0
|
||||||
python3 -m cibuildwheel --output-dir wheelhouse
|
python3 -m cibuildwheel --output-dir wheelhouse
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: wheelhouse/
|
path: wheelhouse/
|
||||||
@@ -36,13 +36,15 @@ jobs:
|
|||||||
osx-wheels:
|
osx-wheels:
|
||||||
working_directory: ~/osx-wheels
|
working_directory: ~/osx-wheels
|
||||||
macos:
|
macos:
|
||||||
xcode: 12.5.1
|
xcode: 15.4.0
|
||||||
|
resource_class: macos.m1.medium.gen1
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
name: Build the OS X wheels.
|
name: Build the OS X wheels.
|
||||||
command: |
|
command: |
|
||||||
pip3 install cibuildwheel==2.18.0
|
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
|
||||||
|
pip3 install cibuildwheel==2.20.0
|
||||||
cibuildwheel --output-dir wheelhouse
|
cibuildwheel --output-dir wheelhouse
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: wheelhouse/
|
path: wheelhouse/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
||||||
install_cibuildwheel_script:
|
install_cibuildwheel_script:
|
||||||
- python -m pip install cibuildwheel==2.18.0
|
- python -m pip install cibuildwheel==2.20.0
|
||||||
run_cibuildwheel_script:
|
run_cibuildwheel_script:
|
||||||
- cibuildwheel
|
- cibuildwheel
|
||||||
wheels_artifacts:
|
wheels_artifacts:
|
||||||
@@ -11,10 +11,11 @@ macos_task:
|
|||||||
name: Build macOS x86_64 and arm64 wheels.
|
name: Build macOS x86_64 and arm64 wheels.
|
||||||
macos_instance:
|
macos_instance:
|
||||||
image: ghcr.io/cirruslabs/macos-sonoma-xcode
|
image: ghcr.io/cirruslabs/macos-sonoma-xcode
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PATH: /opt/homebrew/opt/python@3.10/libexec/bin:$PATH
|
VENV_ROOT: ${HOME}/venv-cibuildwheel
|
||||||
|
PATH: ${VENV_ROOT}/bin:${PATH}
|
||||||
CIBW_ARCHS_MACOS: x86_64 arm64
|
CIBW_ARCHS_MACOS: x86_64 arm64
|
||||||
install_pre_requirements_script:
|
install_pre_requirements_script:
|
||||||
- brew install python@3.10
|
- brew install python@3.12
|
||||||
|
- python3.12 -m venv ${VENV_ROOT}
|
||||||
<<: *BUILD_AND_STORE_WHEELS
|
<<: *BUILD_AND_STORE_WHEELS
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
||||||
install_cibuildwheel_script:
|
install_cibuildwheel_script:
|
||||||
- python -m pip install cibuildwheel==2.18.0
|
- python -m pip install cibuildwheel==2.20.0
|
||||||
run_cibuildwheel_script:
|
run_cibuildwheel_script:
|
||||||
- cibuildwheel
|
- cibuildwheel
|
||||||
wheels_artifacts:
|
wheels_artifacts:
|
||||||
@@ -15,9 +15,14 @@ linux_x86_task:
|
|||||||
platform: linux
|
platform: linux
|
||||||
cpu: 4
|
cpu: 4
|
||||||
memory: 4G
|
memory: 4G
|
||||||
|
env:
|
||||||
|
VENV_ROOT: ${HOME}/venv-cibuildwheel
|
||||||
|
PATH: ${VENV_ROOT}/bin:${PATH}
|
||||||
install_pre_requirements_script:
|
install_pre_requirements_script:
|
||||||
- apt install -y python3-venv python-is-python3
|
- add-apt-repository -y ppa:deadsnakes/ppa
|
||||||
|
- apt-get update
|
||||||
|
- apt-get install -y python3.12-venv
|
||||||
|
- python3.12 -m venv ${VENV_ROOT}
|
||||||
<<: *BUILD_AND_STORE_WHEELS
|
<<: *BUILD_AND_STORE_WHEELS
|
||||||
|
|
||||||
linux_aarch64_task:
|
linux_aarch64_task:
|
||||||
@@ -29,9 +34,14 @@ linux_aarch64_task:
|
|||||||
platform: linux
|
platform: linux
|
||||||
cpu: 4
|
cpu: 4
|
||||||
memory: 4G
|
memory: 4G
|
||||||
|
env:
|
||||||
|
VENV_ROOT: ${HOME}/venv-cibuildwheel
|
||||||
|
PATH: ${VENV_ROOT}/bin:${PATH}
|
||||||
install_pre_requirements_script:
|
install_pre_requirements_script:
|
||||||
- apt install -y python3-venv python-is-python3
|
- add-apt-repository -y ppa:deadsnakes/ppa
|
||||||
|
- apt-get update
|
||||||
|
- apt-get install -y python3.12-venv
|
||||||
|
- python3.12 -m venv ${VENV_ROOT}
|
||||||
<<: *BUILD_AND_STORE_WHEELS
|
<<: *BUILD_AND_STORE_WHEELS
|
||||||
|
|
||||||
windows_x86_task:
|
windows_x86_task:
|
||||||
@@ -42,7 +52,7 @@ windows_x86_task:
|
|||||||
memory: 4G
|
memory: 4G
|
||||||
|
|
||||||
install_pre_requirements_script:
|
install_pre_requirements_script:
|
||||||
- choco install -y --no-progress python3 --version 3.10.6
|
- choco install -y --no-progress python3 --version 3.12.4
|
||||||
- refreshenv
|
- refreshenv
|
||||||
- echo PATH=%PATH% >> "%CIRRUS_ENV%"
|
- echo PATH=%PATH% >> "%CIRRUS_ENV%"
|
||||||
<<: *BUILD_AND_STORE_WHEELS
|
<<: *BUILD_AND_STORE_WHEELS
|
||||||
@@ -51,9 +61,10 @@ macos_arm64_task:
|
|||||||
name: Build macOS arm64 wheels.
|
name: Build macOS arm64 wheels.
|
||||||
macos_instance:
|
macos_instance:
|
||||||
image: ghcr.io/cirruslabs/macos-sonoma-xcode
|
image: ghcr.io/cirruslabs/macos-sonoma-xcode
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PATH: /opt/homebrew/opt/python@3.10/libexec/bin:$PATH
|
VENV_ROOT: ${HOME}/venv-cibuildwheel
|
||||||
|
PATH: ${VENV_ROOT}/bin:${PATH}
|
||||||
install_pre_requirements_script:
|
install_pre_requirements_script:
|
||||||
- brew install python@3.10
|
- brew install python@3.12
|
||||||
|
- python3.12 -m venv ${VENV_ROOT}
|
||||||
<<: *BUILD_AND_STORE_WHEELS
|
<<: *BUILD_AND_STORE_WHEELS
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: pypa/cibuildwheel@v2.18.0
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: pypa/cibuildwheel@v2.18.0
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
# env:
|
# env:
|
||||||
# CIBW_SOME_OPTION: value
|
# CIBW_SOME_OPTION: value
|
||||||
# ...
|
# ...
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
platforms: all
|
platforms: all
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: pypa/cibuildwheel@v2.18.0
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
env:
|
env:
|
||||||
# configure cibuildwheel to build native archs ('auto'), and some
|
# configure cibuildwheel to build native archs ('auto'), and some
|
||||||
# emulated ones
|
# emulated ones
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
linux:
|
linux:
|
||||||
image: python:3.8
|
image: python:3.12
|
||||||
# make a docker daemon available for cibuildwheel to use
|
# make a docker daemon available for cibuildwheel to use
|
||||||
services:
|
services:
|
||||||
- name: docker:dind
|
- name: docker:dind
|
||||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||||
command: ["dockerd-entrypoint.sh"]
|
command: ["dockerd-entrypoint.sh"]
|
||||||
variables:
|
variables:
|
||||||
DOCKER_HOST: tcp://docker:2375/
|
|
||||||
DOCKER_DRIVER: overlay2
|
DOCKER_DRIVER: overlay2
|
||||||
# See https://github.com/docker-library/docker/pull/166
|
# See https://github.com/docker-library/docker/pull/166
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
script:
|
script:
|
||||||
- curl -sSL https://get.docker.com/ | sh
|
- curl -sSL https://get.docker.com/ | sh
|
||||||
- python -m pip install cibuildwheel==2.18.0
|
- python -m pip install cibuildwheel==2.20.0
|
||||||
- cibuildwheel --output-dir wheelhouse
|
- cibuildwheel --output-dir wheelhouse
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
@@ -21,13 +20,25 @@ linux:
|
|||||||
windows:
|
windows:
|
||||||
image: mcr.microsoft.com/windows/servercore:1809
|
image: mcr.microsoft.com/windows/servercore:1809
|
||||||
before_script:
|
before_script:
|
||||||
- choco install python -y --version 3.8.6
|
- choco install python -y --version 3.12.4
|
||||||
- choco install git.install -y
|
- choco install git.install -y
|
||||||
- py -m pip install cibuildwheel==2.18.0
|
- py -m pip install cibuildwheel==2.20.0
|
||||||
script:
|
script:
|
||||||
- py -m cibuildwheel --output-dir wheelhouse --platform windows
|
- py -m cibuildwheel --output-dir wheelhouse --platform windows
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
- wheelhouse/
|
- wheelhouse/
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- saas-windows-medium-amd64
|
||||||
|
|
||||||
|
macos:
|
||||||
|
image: macos-14-xcode-15
|
||||||
|
before_script:
|
||||||
|
- python3 -m pip install cibuildwheel==2.20.0
|
||||||
|
script:
|
||||||
|
- python3 -m cibuildwheel --output-dir wheelhouse
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- wheelhouse/
|
||||||
|
tags:
|
||||||
|
- saas-macos-medium-m1
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
linux:
|
linux:
|
||||||
image: python:3.8
|
image: python:3.12
|
||||||
# make a docker daemon available for cibuildwheel to use
|
# make a docker daemon available for cibuildwheel to use
|
||||||
services:
|
services:
|
||||||
- name: docker:dind
|
- name: docker:dind
|
||||||
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
entrypoint: ["env", "-u", "DOCKER_HOST"]
|
||||||
command: ["dockerd-entrypoint.sh"]
|
command: ["dockerd-entrypoint.sh"]
|
||||||
variables:
|
variables:
|
||||||
DOCKER_HOST: tcp://docker:2375/
|
|
||||||
DOCKER_DRIVER: overlay2
|
DOCKER_DRIVER: overlay2
|
||||||
# See https://github.com/docker-library/docker/pull/166
|
# See https://github.com/docker-library/docker/pull/166
|
||||||
DOCKER_TLS_CERTDIR: ""
|
DOCKER_TLS_CERTDIR: ""
|
||||||
@@ -14,7 +13,7 @@ linux:
|
|||||||
- curl -sSL https://get.docker.com/ | sh
|
- curl -sSL https://get.docker.com/ | sh
|
||||||
# Warning: This is extremely slow, be careful with how many wheels you build
|
# Warning: This is extremely slow, be careful with how many wheels you build
|
||||||
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||||
- python -m pip install cibuildwheel==2.18.0
|
- python -m pip install cibuildwheel==2.20.0
|
||||||
# Assuming your CI runner's default architecture is x86_64...
|
# Assuming your CI runner's default architecture is x86_64...
|
||||||
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
|
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
language: python
|
language: python
|
||||||
python: "3.9"
|
python: "3.12"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
@@ -14,13 +14,13 @@ jobs:
|
|||||||
- os: windows
|
- os: windows
|
||||||
language: shell
|
language: shell
|
||||||
before_install:
|
before_install:
|
||||||
- choco upgrade python -y --version 3.8.6
|
- choco upgrade python -y --version 3.12.4
|
||||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
- export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
|
||||||
# make sure it's on PATH as 'python3'
|
# make sure it's on PATH as 'python3'
|
||||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- python3 -m pip install cibuildwheel==2.18.0
|
- python3 -m pip install cibuildwheel==2.20.0
|
||||||
|
|
||||||
script:
|
script:
|
||||||
# build the wheels, put them into './dist'
|
# build the wheels, put them into './dist'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
language: python
|
language: python
|
||||||
python: "3.9"
|
python: "3.12"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
@@ -20,13 +20,13 @@ jobs:
|
|||||||
- os: windows
|
- os: windows
|
||||||
language: shell
|
language: shell
|
||||||
before_install:
|
before_install:
|
||||||
- choco upgrade python -y --version 3.8.6
|
- choco upgrade python -y --version 3.12.4
|
||||||
- export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
- export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
|
||||||
# make sure it's on PATH as 'python3'
|
# make sure it's on PATH as 'python3'
|
||||||
- ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- python3 -m pip install cibuildwheel==2.18.0
|
- python3 -m pip install cibuildwheel==2.20.0
|
||||||
|
|
||||||
script:
|
script:
|
||||||
# build the wheels, put them into './wheelhouse'
|
# build the wheels, put them into './wheelhouse'
|
||||||
|
|||||||
@@ -8,17 +8,15 @@
|
|||||||
os: linux
|
os: linux
|
||||||
dist: focal
|
dist: focal
|
||||||
language: python
|
language: python
|
||||||
python:
|
python: "3.12"
|
||||||
- 3.7
|
|
||||||
- 3.8
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- |
|
- |
|
||||||
if [[ "$TRAVIS_OS_NAME" = windows ]]; then
|
if [[ "$TRAVIS_OS_NAME" = windows ]]; then
|
||||||
choco upgrade python -y --version 3.8.6
|
choco upgrade python -y --version 3.12.4
|
||||||
export PATH="/c/Python38:/c/Python38/Scripts:$PATH"
|
export PATH="/c/Python312:/c/Python312/Scripts:$PATH"
|
||||||
# make sure it's on PATH as 'python3'
|
# make sure it's on PATH as 'python3'
|
||||||
ln -s /c/Python38/python.exe /c/Python38/python3.exe
|
ln -s /c/Python312/python.exe /c/Python312/python3.exe
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@@ -54,7 +52,7 @@ jobs:
|
|||||||
- stage: deploy
|
- stage: deploy
|
||||||
name: Build and deploy Linux wheels
|
name: Build and deploy Linux wheels
|
||||||
services: docker
|
services: docker
|
||||||
install: python3 -m pip install cibuildwheel==2.18.0 twine
|
install: python3 -m pip install cibuildwheel==2.20.0 twine
|
||||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||||
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
||||||
# Deploy on windows
|
# Deploy on windows
|
||||||
@@ -62,7 +60,7 @@ jobs:
|
|||||||
name: Build and deploy Windows wheels
|
name: Build and deploy Windows wheels
|
||||||
os: windows
|
os: windows
|
||||||
language: shell
|
language: shell
|
||||||
install: python3 -m pip install cibuildwheel==2.18.0 twine
|
install: python3 -m pip install cibuildwheel==2.20.0 twine
|
||||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||||
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
||||||
|
|
||||||
|
|||||||
@@ -49,3 +49,5 @@ plugins:
|
|||||||
module_name: docs/main
|
module_name: docs/main
|
||||||
j2_variable_start_string: «
|
j2_variable_start_string: «
|
||||||
j2_variable_end_string: »
|
j2_variable_end_string: »
|
||||||
|
on_error_fail: true
|
||||||
|
on_undefined: strict
|
||||||
|
|||||||
+54
-20
@@ -4,15 +4,21 @@ import os
|
|||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import nox
|
import nox
|
||||||
|
|
||||||
|
nox.needs_version = ">=2024.4.15"
|
||||||
nox.options.sessions = ["lint", "pylint", "check_manifest", "tests"]
|
nox.options.sessions = ["lint", "pylint", "check_manifest", "tests"]
|
||||||
|
nox.options.default_venv_backend = "uv|virtualenv"
|
||||||
|
|
||||||
DIR = Path(__file__).parent.resolve()
|
DIR = Path(__file__).parent.resolve()
|
||||||
|
|
||||||
if os.environ.get("CI", None):
|
|
||||||
nox.options.error_on_missing_interpreters = True
|
def install_and_run(session: nox.Session, script: str, *args: str, **kwargs: Any) -> str | None:
|
||||||
|
deps = nox.project.load_toml(script)["dependencies"]
|
||||||
|
session.install(*deps)
|
||||||
|
return session.run("python", script, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@nox.session
|
@nox.session
|
||||||
@@ -20,11 +26,11 @@ def tests(session: nox.Session) -> None:
|
|||||||
"""
|
"""
|
||||||
Run the unit and regular tests.
|
Run the unit and regular tests.
|
||||||
"""
|
"""
|
||||||
unit_test_args = ["--run-docker"] if sys.platform.startswith("linux") else []
|
|
||||||
session.install("-e.[test]")
|
session.install("-e.[test]")
|
||||||
if session.posargs:
|
if session.posargs:
|
||||||
session.run("pytest", *session.posargs)
|
session.run("pytest", *session.posargs)
|
||||||
else:
|
else:
|
||||||
|
unit_test_args = ["--run-docker"] if sys.platform.startswith("linux") else []
|
||||||
session.run("pytest", "unit_test", *unit_test_args)
|
session.run("pytest", "unit_test", *unit_test_args)
|
||||||
session.run("pytest", "test", "-x", "--durations", "0", "--timeout=2400", "test")
|
session.run("pytest", "test", "-x", "--durations", "0", "--timeout=2400", "test")
|
||||||
|
|
||||||
@@ -44,8 +50,7 @@ def pylint(session: nox.Session) -> None:
|
|||||||
Run pylint.
|
Run pylint.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = "cibuildwheel @ ." if getattr(session.virtualenv, "venv_backend", "") == "uv" else "."
|
session.install("pylint>=3.2", "-e.")
|
||||||
session.install("pylint", name)
|
|
||||||
session.run("pylint", "cibuildwheel", *session.posargs)
|
session.run("pylint", "cibuildwheel", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +70,9 @@ def update_constraints(session: nox.Session) -> None:
|
|||||||
Update the dependencies inplace.
|
Update the dependencies inplace.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if getattr(session.virtualenv, "venv_backend", "") != "uv":
|
resources = Path("cibuildwheel/resources")
|
||||||
|
|
||||||
|
if session.venv_backend != "uv":
|
||||||
session.install("uv>=0.1.23")
|
session.install("uv>=0.1.23")
|
||||||
|
|
||||||
for minor_version in range(7, 14):
|
for minor_version in range(7, 14):
|
||||||
@@ -74,42 +81,62 @@ def update_constraints(session: nox.Session) -> None:
|
|||||||
# CUSTOM_COMPILE_COMMAND is a pip-compile option that tells users how to
|
# CUSTOM_COMPILE_COMMAND is a pip-compile option that tells users how to
|
||||||
# regenerate the constraints files
|
# regenerate the constraints files
|
||||||
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
|
env["UV_CUSTOM_COMPILE_COMMAND"] = f"nox -s {session.name}"
|
||||||
|
output_file = resources / f"constraints-python{python_version.replace('.', '')}.txt"
|
||||||
session.run(
|
session.run(
|
||||||
"uv",
|
"uv",
|
||||||
"pip",
|
"pip",
|
||||||
"compile",
|
"compile",
|
||||||
f"--python-version={python_version}",
|
f"--python-version={python_version}",
|
||||||
"--upgrade",
|
"--upgrade",
|
||||||
"cibuildwheel/resources/constraints.in",
|
resources / "constraints.in",
|
||||||
f"--output-file=cibuildwheel/resources/constraints-python{python_version.replace('.', '')}.txt",
|
f"--output-file={output_file}",
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
RESOURCES = DIR / "cibuildwheel" / "resources"
|
|
||||||
shutil.copyfile(
|
shutil.copyfile(
|
||||||
RESOURCES / "constraints-python312.txt",
|
resources / "constraints-python312.txt",
|
||||||
RESOURCES / "constraints.txt",
|
resources / "constraints.txt",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
build_platforms = nox.project.load_toml(resources / "build-platforms.toml")
|
||||||
|
pyodides = build_platforms["pyodide"]["python_configurations"]
|
||||||
|
for pyodide in pyodides:
|
||||||
|
python_version = ".".join(pyodide["version"].split(".")[:2])
|
||||||
|
pyodide_version = pyodide["pyodide_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}")
|
||||||
|
session.run(
|
||||||
|
"uv",
|
||||||
|
"pip",
|
||||||
|
"compile",
|
||||||
|
f"--python-version={python_version}",
|
||||||
|
"--upgrade",
|
||||||
|
tmp_file,
|
||||||
|
f"--output-file={output_file}",
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@nox.session
|
@nox.session
|
||||||
def update_pins(session: nox.Session) -> None:
|
def update_pins(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Update the python, docker and virtualenv pins version inplace.
|
Update the python, docker and virtualenv pins version inplace.
|
||||||
"""
|
"""
|
||||||
session.install("-e", ".[bin]")
|
session.install("-e.[bin]")
|
||||||
session.run("python", "bin/update_pythons.py", "--force")
|
session.run("python", "bin/update_pythons.py", "--force")
|
||||||
session.run("python", "bin/update_docker.py")
|
session.run("python", "bin/update_docker.py")
|
||||||
session.run("python", "bin/update_virtualenv.py", "--force")
|
session.run("python", "bin/update_virtualenv.py", "--force")
|
||||||
|
session.run("python", "bin/update_nodejs.py", "--force")
|
||||||
|
|
||||||
|
|
||||||
@nox.session
|
@nox.session(reuse_venv=True)
|
||||||
def update_proj(session: nox.Session) -> None:
|
def update_proj(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Update the README inplace.
|
Update the README inplace.
|
||||||
"""
|
"""
|
||||||
session.install("-e.[bin]")
|
install_and_run(
|
||||||
session.run(
|
session,
|
||||||
"python",
|
|
||||||
"bin/projects.py",
|
"bin/projects.py",
|
||||||
"docs/data/projects.yml",
|
"docs/data/projects.yml",
|
||||||
*session.posargs,
|
*session.posargs,
|
||||||
@@ -121,19 +148,26 @@ def generate_schema(session: nox.Session) -> None:
|
|||||||
"""
|
"""
|
||||||
Generate the cibuildwheel.schema.json file.
|
Generate the cibuildwheel.schema.json file.
|
||||||
"""
|
"""
|
||||||
session.install("pyyaml")
|
output = install_and_run(session, "bin/generate_schema.py", silent=True)
|
||||||
output = session.run("python", "bin/generate_schema.py", silent=True)
|
|
||||||
assert isinstance(output, str)
|
assert isinstance(output, str)
|
||||||
DIR.joinpath("cibuildwheel/resources/cibuildwheel.schema.json").write_text(output)
|
DIR.joinpath("cibuildwheel/resources/cibuildwheel.schema.json").write_text(output)
|
||||||
|
|
||||||
|
|
||||||
@nox.session(python="3.9")
|
@nox.session(reuse_venv=True)
|
||||||
|
def bump_version(session: nox.Session) -> None:
|
||||||
|
"""
|
||||||
|
Bump cibuildwheel's version. Interactive.
|
||||||
|
"""
|
||||||
|
install_and_run(session, "bin/bump_version.py")
|
||||||
|
|
||||||
|
|
||||||
|
@nox.session(python="3.12")
|
||||||
def docs(session: nox.Session) -> None:
|
def docs(session: nox.Session) -> None:
|
||||||
"""
|
"""
|
||||||
Build the docs. Will serve unless --non-interactive
|
Build the docs. Will serve unless --non-interactive
|
||||||
"""
|
"""
|
||||||
session.install("-e.[docs]")
|
session.install("-e.[docs]")
|
||||||
session.run("mkdocs", "serve" if session.interactive else "build")
|
session.run("mkdocs", "serve" if session.interactive else "build", "--strict", *session.posargs)
|
||||||
|
|
||||||
|
|
||||||
@nox.session
|
@nox.session
|
||||||
|
|||||||
+95
-21
@@ -1,9 +1,96 @@
|
|||||||
[build-system]
|
[build-system]
|
||||||
requires = [
|
requires = ["hatchling"]
|
||||||
"setuptools>=42",
|
build-backend = "hatchling.build"
|
||||||
]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "cibuildwheel"
|
||||||
|
version = "2.20.0"
|
||||||
|
description = "Build Python wheels on CI with minimal configuration."
|
||||||
|
readme = "README.md"
|
||||||
|
license = "BSD-2-Clause"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
authors = [
|
||||||
|
{ name = "Joe Rickerby", email = "joerick@mac.com" },
|
||||||
|
]
|
||||||
|
keywords = [
|
||||||
|
"appveyor",
|
||||||
|
"ci",
|
||||||
|
"linux",
|
||||||
|
"macos",
|
||||||
|
"packaging",
|
||||||
|
"pypi",
|
||||||
|
"travis",
|
||||||
|
"wheel",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"Natural Language :: English",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
"Topic :: Software Development :: Build Tools",
|
||||||
|
]
|
||||||
|
dependencies = [
|
||||||
|
"bashlex!=0.13",
|
||||||
|
"bracex",
|
||||||
|
"certifi",
|
||||||
|
"filelock",
|
||||||
|
"packaging>=20.9",
|
||||||
|
"platformdirs",
|
||||||
|
"tomli;python_version < '3.11'",
|
||||||
|
"typing-extensions>=4.1.0;python_version < '3.11'",
|
||||||
|
]
|
||||||
|
|
||||||
|
[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]
|
||||||
|
cibuildwheel = "cibuildwheel.__main__:main"
|
||||||
|
|
||||||
|
[project.entry-points."validate_pyproject.tool_schema"]
|
||||||
|
cibuildwheel = "cibuildwheel.schema:get_schema"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Changelog = "https://github.com/pypa/cibuildwheel#changelog"
|
||||||
|
Documentation = "https://cibuildwheel.pypa.io"
|
||||||
|
Homepage = "https://github.com/pypa/cibuildwheel"
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
minversion = "6.0"
|
minversion = "6.0"
|
||||||
@@ -49,6 +136,8 @@ disallow_untyped_decorators = true
|
|||||||
[[tool.mypy.overrides]]
|
[[tool.mypy.overrides]]
|
||||||
module = [
|
module = [
|
||||||
"setuptools",
|
"setuptools",
|
||||||
|
"setuptools._distutils", # needed even if only directly import setuptools._distutils.util
|
||||||
|
"setuptools._distutils.util",
|
||||||
"pytest", # ignored in pre-commit to speed up check
|
"pytest", # ignored in pre-commit to speed up check
|
||||||
"bashlex",
|
"bashlex",
|
||||||
"bashlex.*",
|
"bashlex.*",
|
||||||
@@ -57,21 +146,6 @@ module = [
|
|||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
|
||||||
[tool.check-manifest]
|
|
||||||
ignore = [
|
|
||||||
".*",
|
|
||||||
".circleci/**",
|
|
||||||
"test/**",
|
|
||||||
"unit_test/**",
|
|
||||||
"docs/**",
|
|
||||||
"examples/**",
|
|
||||||
"bin/**",
|
|
||||||
"*.yml",
|
|
||||||
"CI.md", # TODO: can change test/test_ssl and remove this
|
|
||||||
"requirements-dev.txt",
|
|
||||||
"noxfile.py",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.pylint]
|
[tool.pylint]
|
||||||
py-version = "3.8"
|
py-version = "3.8"
|
||||||
jobs = "0"
|
jobs = "0"
|
||||||
@@ -106,13 +180,12 @@ messages_control.disable = [
|
|||||||
"wrong-import-position",
|
"wrong-import-position",
|
||||||
"unused-argument", # Handled by Ruff
|
"unused-argument", # Handled by Ruff
|
||||||
"broad-exception-raised", # Could be improved eventually
|
"broad-exception-raised", # Could be improved eventually
|
||||||
|
"consider-using-in", # MyPy can't narrow "in"
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
target-version = "py38"
|
|
||||||
line-length = 100
|
line-length = 100
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
extend-select = [
|
extend-select = [
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
@@ -162,6 +235,7 @@ flake8-unused-arguments.ignore-variadic-names = true
|
|||||||
[tool.ruff.lint.per-file-ignores]
|
[tool.ruff.lint.per-file-ignores]
|
||||||
"unit_test/*" = ["PLC1901"]
|
"unit_test/*" = ["PLC1901"]
|
||||||
"cibuildwheel/_compat/**.py" = ["TID251"]
|
"cibuildwheel/_compat/**.py" = ["TID251"]
|
||||||
|
"bin/*" = ["TID251"]
|
||||||
|
|
||||||
[tool.repo-review]
|
[tool.repo-review]
|
||||||
ignore = ["PC170", "PP303"]
|
ignore = ["PC170", "PP303"]
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
[metadata]
|
|
||||||
name = cibuildwheel
|
|
||||||
version = 2.18.0
|
|
||||||
description = Build Python wheels on CI with minimal configuration.
|
|
||||||
long_description = file: README.md
|
|
||||||
long_description_content_type = text/markdown
|
|
||||||
url = https://github.com/pypa/cibuildwheel
|
|
||||||
author = Joe Rickerby
|
|
||||||
author_email = joerick@mac.com
|
|
||||||
license = BSD-2-Clause
|
|
||||||
license_files = LICENSE
|
|
||||||
classifiers =
|
|
||||||
Development Status :: 5 - Production/Stable
|
|
||||||
Intended Audience :: Developers
|
|
||||||
License :: OSI Approved :: BSD License
|
|
||||||
Natural Language :: English
|
|
||||||
Programming Language :: Python :: 3
|
|
||||||
Programming Language :: Python :: 3 :: Only
|
|
||||||
Programming Language :: Python :: 3.8
|
|
||||||
Programming Language :: Python :: 3.9
|
|
||||||
Programming Language :: Python :: 3.10
|
|
||||||
Programming Language :: Python :: 3.11
|
|
||||||
Programming Language :: Python :: 3.12
|
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
|
||||||
Topic :: Software Development :: Build Tools
|
|
||||||
keywords = ci,wheel,packaging,pypi,travis,appveyor,macos,linux,windows
|
|
||||||
project_urls =
|
|
||||||
Changelog=https://github.com/pypa/cibuildwheel#changelog
|
|
||||||
Documentation=https://cibuildwheel.pypa.io/
|
|
||||||
|
|
||||||
[options]
|
|
||||||
packages = find:
|
|
||||||
install_requires =
|
|
||||||
bashlex!=0.13
|
|
||||||
bracex
|
|
||||||
certifi
|
|
||||||
filelock
|
|
||||||
packaging>=20.9
|
|
||||||
platformdirs
|
|
||||||
tomli;python_version < '3.11'
|
|
||||||
typing-extensions>=4.1.0;python_version < '3.11'
|
|
||||||
python_requires = >=3.8
|
|
||||||
include_package_data = True
|
|
||||||
zip_safe = False
|
|
||||||
|
|
||||||
[options.packages.find]
|
|
||||||
include =
|
|
||||||
cibuildwheel
|
|
||||||
|
|
||||||
[options.entry_points]
|
|
||||||
console_scripts =
|
|
||||||
cibuildwheel = cibuildwheel.__main__:main
|
|
||||||
validate_pyproject.tool_schema =
|
|
||||||
cibuildwheel = cibuildwheel.schema:get_schema
|
|
||||||
|
|
||||||
[options.package_data]
|
|
||||||
cibuildwheel = resources/*
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
extras = {
|
|
||||||
"docs": [
|
|
||||||
"mkdocs-include-markdown-plugin==2.8.0",
|
|
||||||
"mkdocs==1.3.1",
|
|
||||||
"jinja2>=3.1.2",
|
|
||||||
"pymdown-extensions",
|
|
||||||
"mkdocs-macros-plugin",
|
|
||||||
],
|
|
||||||
"test": [
|
|
||||||
"jinja2",
|
|
||||||
"pytest>=6",
|
|
||||||
"pytest-timeout",
|
|
||||||
"pytest-xdist",
|
|
||||||
"build",
|
|
||||||
"tomli_w",
|
|
||||||
"validate-pyproject",
|
|
||||||
],
|
|
||||||
"bin": [
|
|
||||||
"click",
|
|
||||||
"pip-tools",
|
|
||||||
"pygithub",
|
|
||||||
"pyyaml",
|
|
||||||
"requests",
|
|
||||||
"rich>=9.6",
|
|
||||||
"packaging>=21.0",
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
extras["dev"] = [
|
|
||||||
*extras["test"],
|
|
||||||
*extras["bin"],
|
|
||||||
]
|
|
||||||
|
|
||||||
setup(extras_require=extras)
|
|
||||||
+24
-9
@@ -6,14 +6,18 @@ from typing import Generator
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from cibuildwheel.util import detect_ci_provider
|
from cibuildwheel.util import detect_ci_provider, find_uv
|
||||||
|
|
||||||
from .utils import platform
|
from .utils import EMULATED_ARCHS, platform
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser) -> None:
|
def pytest_addoption(parser) -> None:
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--run-emulation", action="store_true", default=False, help="run emulation tests"
|
"--run-emulation",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
help="run emulation tests",
|
||||||
|
choices=("all", *EMULATED_ARCHS),
|
||||||
)
|
)
|
||||||
parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests")
|
parser.addoption("--run-podman", action="store_true", default=False, help="run podman tests")
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
@@ -24,14 +28,25 @@ def pytest_addoption(parser) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(params=["pip", "build"])
|
||||||
params=[{"CIBW_BUILD_FRONTEND": "pip"}, {"CIBW_BUILD_FRONTEND": "build"}], ids=["pip", "build"]
|
def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
|
||||||
)
|
frontend = request.param
|
||||||
def build_frontend_env(request) -> dict[str, str]:
|
if platform == "pyodide" and frontend == "pip":
|
||||||
return request.param # type: ignore[no-any-return]
|
pytest.skip("Can't use pip as build frontend for pyodide platform")
|
||||||
|
|
||||||
|
return {"CIBW_BUILD_FRONTEND": frontend}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture
|
||||||
|
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]:
|
||||||
|
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"]
|
||||||
|
if frontend != "build" or platform == "pyodide" or find_uv() is None:
|
||||||
|
return build_frontend_env_nouv
|
||||||
|
|
||||||
|
return {"CIBW_BUILD_FRONTEND": "build[uv]"}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
def docker_cleanup() -> Generator[None, None, None]:
|
def docker_cleanup() -> Generator[None, None, None]:
|
||||||
def get_images() -> set[str]:
|
def get_images() -> set[str]:
|
||||||
if detect_ci_provider() is None or platform != "linux":
|
if detect_ci_provider() is None or platform != "linux":
|
||||||
|
|||||||
+11
-3
@@ -69,7 +69,15 @@ def test_build_identifiers(tmp_path):
|
|||||||
), f"{expected_wheels} vs {build_identifiers}"
|
), f"{expected_wheels} vs {build_identifiers}"
|
||||||
|
|
||||||
|
|
||||||
def test_allow_empty(tmp_path):
|
@pytest.mark.parametrize(
|
||||||
|
("add_args", "env_allow_empty"),
|
||||||
|
[
|
||||||
|
(["--allow-empty"], {}),
|
||||||
|
(["--allow-empty"], {"CIBW_ALLOW_EMPTY": "0"}),
|
||||||
|
(None, {"CIBW_ALLOW_EMPTY": "1"}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_allow_empty(tmp_path, add_args, env_allow_empty):
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
basic_project.generate(project_dir)
|
basic_project.generate(project_dir)
|
||||||
|
|
||||||
@@ -77,8 +85,8 @@ def test_allow_empty(tmp_path):
|
|||||||
# without error
|
# without error
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={"CIBW_BUILD": "BUILD_NOTHING_AT_ALL"},
|
add_env={"CIBW_BUILD": "BUILD_NOTHING_AT_ALL", **env_allow_empty},
|
||||||
add_args=["--allow-empty"],
|
add_args=add_args,
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that nothing was built
|
# check that nothing was built
|
||||||
|
|||||||
+32
-11
@@ -13,9 +13,14 @@ build-backend = "setuptools.build_meta"
|
|||||||
limited_api_project = test_projects.new_c_project(
|
limited_api_project = test_projects.new_c_project(
|
||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
r"""
|
r"""
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
|
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 = {}
|
cmdclass = {}
|
||||||
extension_kwargs = {}
|
extension_kwargs = {}
|
||||||
if sys.version_info[:2] >= (3, 8):
|
if CAN_USE_ABI3 and sys.version_info[:2] >= (3, 10):
|
||||||
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
|
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
|
||||||
|
|
||||||
class bdist_wheel_abi3(_bdist_wheel):
|
class bdist_wheel_abi3(_bdist_wheel):
|
||||||
@@ -28,7 +33,7 @@ limited_api_project = test_projects.new_c_project(
|
|||||||
return python, "abi3", plat
|
return python, "abi3", plat
|
||||||
|
|
||||||
cmdclass["bdist_wheel"] = bdist_wheel_abi3
|
cmdclass["bdist_wheel"] = bdist_wheel_abi3
|
||||||
extension_kwargs["define_macros"] = [("Py_LIMITED_API", "0x03080000")]
|
extension_kwargs["define_macros"] = [("Py_LIMITED_API", "0x030A0000")]
|
||||||
extension_kwargs["py_limited_api"] = True
|
extension_kwargs["py_limited_api"] = True
|
||||||
"""
|
"""
|
||||||
),
|
),
|
||||||
@@ -43,20 +48,32 @@ def test_abi3(tmp_path):
|
|||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
limited_api_project.generate(project_dir)
|
limited_api_project.generate(project_dir)
|
||||||
|
|
||||||
|
single_python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_SKIP": "pp* ", # PyPy does not have a Py_LIMITED_API equivalent
|
# free_threaded and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
|
||||||
|
# also limit the number of builds for test performance reasons
|
||||||
|
"CIBW_BUILD": f"cp39-* cp310-* pp310-* {single_python_tag}-* cp313t-*"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [
|
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||||
w.replace("cp38-cp38", "cp38-abi3")
|
if utils.platform == "pyodide":
|
||||||
for w in utils.expected_wheels("spam", "0.1.0")
|
# there's only 1 possible configuration for pyodide, the single_python_tag one
|
||||||
if "-pp" not in w and "-cp39" not in w and "-cp31" not in w
|
expected_wheels = [
|
||||||
]
|
w.replace(f"{single_python_tag}-{single_python_tag}", f"{single_python_tag}-abi3")
|
||||||
|
for w in expected_wheels
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
expected_wheels = [
|
||||||
|
w.replace("cp310-cp310", "cp310-abi3")
|
||||||
|
for w in expected_wheels
|
||||||
|
if "-cp39" in w or "-cp310" in w or "-pp310" in w or "-cp313t" in w
|
||||||
|
]
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -175,9 +192,9 @@ def test_abi_none(tmp_path, capfd):
|
|||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
"CIBW_TEST_COMMAND": "pytest {project}/test",
|
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test",
|
||||||
# limit the number of builds for test performance reasons
|
# limit the number of builds for test performance reasons
|
||||||
"CIBW_BUILD": "cp38-* cp310-* pp39-*",
|
"CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -188,4 +205,8 @@ def test_abi_none(tmp_path, capfd):
|
|||||||
# check that each wheel was built once, and reused
|
# check that each wheel was built once, and reused
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
assert "Building wheel..." in captured.out
|
assert "Building wheel..." in captured.out
|
||||||
assert "Found previously built wheel" in captured.out
|
if utils.platform == "pyodide":
|
||||||
|
# there's only 1 possible configuration for pyodide, we won't see the message expected on following builds
|
||||||
|
assert "Found previously built wheel" not in captured.out
|
||||||
|
else:
|
||||||
|
assert "Found previously built wheel" in captured.out
|
||||||
|
|||||||
+21
-8
@@ -10,13 +10,22 @@ from . import test_projects, utils
|
|||||||
project_with_before_build_asserts = test_projects.new_c_project(
|
project_with_before_build_asserts = test_projects.new_c_project(
|
||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
r"""
|
r"""
|
||||||
# assert that the Python version as written to text_info.txt in the CIBW_BEFORE_ALL step
|
import os
|
||||||
# is the same one as is currently running.
|
|
||||||
with open("text_info.txt") as f:
|
with open("text_info.txt") as f:
|
||||||
stored_text = f.read()
|
stored_text = f.read()
|
||||||
|
|
||||||
print("## stored text: " + stored_text)
|
print("## stored text: " + stored_text)
|
||||||
assert stored_text == "sample text 123"
|
assert stored_text == "sample text 123"
|
||||||
|
|
||||||
|
# assert that the Python version as written to python_prefix.txt in the CIBW_BEFORE_ALL step
|
||||||
|
# is not the same one as is currently running.
|
||||||
|
with open('python_prefix.txt') as f:
|
||||||
|
stored_prefix = f.read()
|
||||||
|
print('stored_prefix', stored_prefix)
|
||||||
|
print('sys.prefix', sys.prefix)
|
||||||
|
# Works around path-comparison bugs caused by short-paths on Windows e.g.
|
||||||
|
# vssadm~1 instead of vssadministrator
|
||||||
|
assert not os.path.samefile(stored_prefix, sys.prefix)
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -30,21 +39,24 @@ def test(tmp_path):
|
|||||||
print("dummy text", file=ff)
|
print("dummy text", file=ff)
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
before_all_command = '''python -c "import os;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))"'''
|
before_all_command = (
|
||||||
|
"""python -c "import os, sys;open('{project}/text_info.txt', 'w').write('sample text '+os.environ.get('TEST_VAL', ''))" && """
|
||||||
|
'''python -c "import sys; open('{project}/python_prefix.txt', 'w').write(sys.prefix)"'''
|
||||||
|
)
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
# write python version information to a temporary file, this is
|
# write python version information to a temporary file, this is
|
||||||
# checked in setup.py
|
# checked in setup.py
|
||||||
"CIBW_BEFORE_ALL": before_all_command,
|
"CIBW_BEFORE_ALL": before_all_command,
|
||||||
"CIBW_BEFORE_ALL_LINUX": f'{before_all_command} && python -c "import sys; assert sys.version_info >= (3, 6)"',
|
"CIBW_BEFORE_ALL_LINUX": f'{before_all_command} && python -c "import sys; assert sys.version_info >= (3, 8)"',
|
||||||
"CIBW_ENVIRONMENT": "TEST_VAL='123'",
|
"CIBW_ENVIRONMENT": "TEST_VAL='123'",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# also check that we got the right wheels
|
# also check that we got the right wheels
|
||||||
(project_dir / "text_info.txt").unlink()
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +84,8 @@ def test_cwd(tmp_path):
|
|||||||
"CIBW_BEFORE_ALL": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
"CIBW_BEFORE_ALL": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||||
"CIBW_BEFORE_ALL_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
"CIBW_BEFORE_ALL_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
+19
-20
@@ -7,33 +7,32 @@ import pytest
|
|||||||
|
|
||||||
from . import test_projects, utils
|
from . import test_projects, utils
|
||||||
|
|
||||||
|
# pyodide does not support building without isolation, need to check the base_prefix
|
||||||
|
SYS_PREFIX = f"sys.{'base_' if utils.platform == 'pyodide' else ''}prefix"
|
||||||
|
|
||||||
|
|
||||||
project_with_before_build_asserts = test_projects.new_c_project(
|
project_with_before_build_asserts = test_projects.new_c_project(
|
||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
r"""
|
rf"""
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# assert that the Python version as written to pythonversion_bb.txt in the CIBW_BEFORE_BUILD step
|
# assert that the Python version as written to pythonversion_bb.txt in the CIBW_BEFORE_BUILD step
|
||||||
# is the same one as is currently running.
|
# is the same one as is currently running.
|
||||||
version_file = 'c:\\pythonversion_bb.txt' if sys.platform == 'win32' else '/tmp/pythonversion_bb.txt'
|
with open('pythonversion_bb.txt') as f:
|
||||||
with open(version_file) as f:
|
|
||||||
stored_version = f.read()
|
stored_version = f.read()
|
||||||
print('stored_version', stored_version)
|
print('stored_version', stored_version)
|
||||||
print('sys.version', sys.version)
|
print('sys.version', sys.version)
|
||||||
assert stored_version == sys.version
|
assert stored_version == sys.version
|
||||||
|
|
||||||
# check that the executable also was written
|
# check that the prefix also was written
|
||||||
executable_file = 'c:\\pythonexecutable_bb.txt' if sys.platform == 'win32' else '/tmp/pythonexecutable_bb.txt'
|
with open('pythonprefix_bb.txt') as f:
|
||||||
with open(executable_file) as f:
|
stored_prefix = f.read()
|
||||||
stored_executable = f.read()
|
print('stored_prefix', stored_prefix)
|
||||||
print('stored_executable', stored_executable)
|
print('{SYS_PREFIX}', {SYS_PREFIX})
|
||||||
print('sys.executable', sys.executable)
|
# Works around path-comparison bugs caused by short-paths on Windows e.g.
|
||||||
|
# vssadm~1 instead of vssadministrator
|
||||||
|
|
||||||
# windows/mac are case insensitive
|
assert os.path.samefile(stored_prefix, {SYS_PREFIX})
|
||||||
stored_path = os.path.realpath(stored_executable).lower()
|
|
||||||
current_path = os.path.realpath(sys.executable).lower()
|
|
||||||
|
|
||||||
# TODO: This is not valid in an virtual environment
|
|
||||||
assert stored_path == current_path, '{0} != {1}'.format(stored_path, current_path)
|
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -44,8 +43,8 @@ def test(tmp_path):
|
|||||||
project_with_before_build_asserts.generate(project_dir)
|
project_with_before_build_asserts.generate(project_dir)
|
||||||
|
|
||||||
before_build = (
|
before_build = (
|
||||||
"""python -c "import sys; open('{output_dir}pythonversion_bb.txt', 'w').write(sys.version)" && """
|
"""python -c "import sys; open('{project}/pythonversion_bb.txt', 'w').write(sys.version)" && """
|
||||||
'''python -c "import sys; open('{output_dir}pythonexecutable_bb.txt', 'w').write(sys.executable)"'''
|
f'''python -c "import sys; open('{{project}}/pythonprefix_bb.txt', 'w').write({SYS_PREFIX})"'''
|
||||||
)
|
)
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
@@ -54,8 +53,7 @@ def test(tmp_path):
|
|||||||
add_env={
|
add_env={
|
||||||
# write python version information to a temporary file, this is
|
# write python version information to a temporary file, this is
|
||||||
# checked in setup.py
|
# checked in setup.py
|
||||||
"CIBW_BEFORE_BUILD": before_build.format(output_dir="/tmp/"),
|
"CIBW_BEFORE_BUILD": before_build,
|
||||||
"CIBW_BEFORE_BUILD_WINDOWS": before_build.format(output_dir=r"c:\\"),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -88,7 +86,8 @@ def test_cwd(tmp_path):
|
|||||||
"CIBW_BEFORE_BUILD": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
"CIBW_BEFORE_BUILD": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||||
"CIBW_BEFORE_BUILD_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
"CIBW_BEFORE_BUILD_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
+24
-11
@@ -6,54 +6,67 @@ before_test_project = test_projects.new_c_project()
|
|||||||
before_test_project.files["test/spam_test.py"] = r"""
|
before_test_project.files["test/spam_test.py"] = r"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
|
||||||
|
PROJECT_DIR = Path(__file__).joinpath("..", "..").resolve()
|
||||||
|
|
||||||
|
|
||||||
class TestBeforeTest(TestCase):
|
class TestBeforeTest(TestCase):
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
# assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step
|
# assert that the Python version as written to pythonversion_bt.txt in the CIBW_BEFORE_TEST step
|
||||||
# is the same one as is currently running.
|
# is the same one as is currently running.
|
||||||
# because of use symlinks in MacOS run this test is also need
|
# because of use symlinks in MacOS run this test is also need
|
||||||
version_file = 'c:\\pythonversion_bt.txt' if sys.platform == 'win32' else '/tmp/pythonversion_bt.txt'
|
stored_version = PROJECT_DIR.joinpath('pythonversion_bt.txt').read_text()
|
||||||
with open(version_file) as f:
|
|
||||||
stored_version = f.read()
|
|
||||||
print('stored_version', stored_version)
|
print('stored_version', stored_version)
|
||||||
print('sys.version', sys.version)
|
print('sys.version', sys.version)
|
||||||
assert stored_version == sys.version
|
assert stored_version == sys.version
|
||||||
|
|
||||||
def test_prefix(self):
|
def test_prefix(self):
|
||||||
# check that the prefix also was written
|
# check that the prefix also was written
|
||||||
prefix_file = 'c:\\pythonprefix_bt.txt' if sys.platform == 'win32' else '/tmp/pythonprefix_bt.txt'
|
stored_prefix = PROJECT_DIR.joinpath('pythonprefix_bt.txt').read_text()
|
||||||
with open(prefix_file) as f:
|
|
||||||
stored_prefix = f.read()
|
|
||||||
print('stored_prefix', stored_prefix)
|
print('stored_prefix', stored_prefix)
|
||||||
print('sys.prefix', sys.prefix)
|
print('sys.prefix', sys.prefix)
|
||||||
# Works around path-comparison bugs caused by short-paths on Windows e.g.
|
# Works around path-comparison bugs caused by short-paths on Windows e.g.
|
||||||
# vssadm~1 instead of vssadministrator
|
# vssadm~1 instead of vssadministrator
|
||||||
|
|
||||||
assert os.stat(stored_prefix) == os.stat(sys.prefix)
|
assert os.path.samefile(stored_prefix, sys.prefix)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def test(tmp_path):
|
def test(tmp_path, build_frontend_env):
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
before_test_project.generate(project_dir)
|
before_test_project.generate(project_dir)
|
||||||
test_project_dir = project_dir / "dependency"
|
test_project_dir = project_dir / "dependency"
|
||||||
test_projects.new_c_project().generate(test_project_dir)
|
test_projects.new_c_project().generate(test_project_dir)
|
||||||
|
|
||||||
|
before_test_steps = [
|
||||||
|
'''python -c "import os, sys; open('{project}/pythonversion_bt.txt', 'w').write(sys.version)"''',
|
||||||
|
'''python -c "import os, sys; open('{project}/pythonprefix_bt.txt', 'w').write(sys.prefix)"''',
|
||||||
|
]
|
||||||
|
|
||||||
|
if utils.platform == "pyodide":
|
||||||
|
before_test_steps.extend(
|
||||||
|
["pyodide build {project}/dependency", "pip install --find-links dist/ spam"]
|
||||||
|
)
|
||||||
|
elif build_frontend_env["CIBW_BUILD_FRONTEND"] in {"pip", "build"}:
|
||||||
|
before_test_steps.append("python -m pip install {project}/dependency")
|
||||||
|
|
||||||
|
before_test = " && ".join(before_test_steps)
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
# write python version information to a temporary file, this is
|
# write python version information to a temporary file, this is
|
||||||
# checked in setup.py
|
# checked in setup.py
|
||||||
"CIBW_BEFORE_TEST": """python -c "import sys; open('/tmp/pythonversion_bt.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix_bt.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency""",
|
"CIBW_BEFORE_TEST": before_test,
|
||||||
"CIBW_BEFORE_TEST_WINDOWS": """python -c "import sys; open('c:\\pythonversion_bt.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix_bt.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency""",
|
|
||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": "false || pytest {project}/test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "pytest {project}/test",
|
"CIBW_TEST_COMMAND_WINDOWS": "pytest {project}/test",
|
||||||
|
**build_frontend_env,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,21 +6,24 @@ from . import utils
|
|||||||
from .test_projects.c import new_c_project
|
from .test_projects.c import new_c_project
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("frontend_name", ["pip", "build"])
|
@pytest.mark.parametrize(
|
||||||
|
"frontend_name",
|
||||||
|
[
|
||||||
|
pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")),
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_build_frontend_args(tmp_path, capfd, frontend_name):
|
def test_build_frontend_args(tmp_path, capfd, frontend_name):
|
||||||
project = new_c_project()
|
project = new_c_project()
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
project.generate(project_dir)
|
project.generate(project_dir)
|
||||||
|
|
||||||
# the build will fail because the frontend is called with '-h' - it prints the help message
|
# the build will fail because the frontend is called with '-h' - it prints the help message
|
||||||
|
add_env = {"CIBW_BUILD_FRONTEND": f"{frontend_name}; args: -h"}
|
||||||
|
if utils.platform == "pyodide":
|
||||||
|
add_env["TERM"] = "dumb" # disable color / style
|
||||||
with pytest.raises(subprocess.CalledProcessError):
|
with pytest.raises(subprocess.CalledProcessError):
|
||||||
utils.cibuildwheel_run(
|
utils.cibuildwheel_run(project_dir, add_env=add_env, single_python=True)
|
||||||
project_dir,
|
|
||||||
add_env={
|
|
||||||
"CIBW_BUILD": "cp311-*",
|
|
||||||
"CIBW_BUILD_FRONTEND": f"{frontend_name}; args: -h",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
print(captured.out)
|
print(captured.out)
|
||||||
@@ -29,6 +32,8 @@ def test_build_frontend_args(tmp_path, capfd, frontend_name):
|
|||||||
if frontend_name == "pip":
|
if frontend_name == "pip":
|
||||||
assert "Usage:" in captured.out
|
assert "Usage:" in captured.out
|
||||||
assert "Wheel Options:" in captured.out
|
assert "Wheel Options:" in captured.out
|
||||||
|
elif utils.platform == "pyodide":
|
||||||
|
assert "Usage: pyodide build" in captured.out
|
||||||
else:
|
else:
|
||||||
assert "usage:" in captured.out
|
assert "usage:" in captured.out
|
||||||
assert "A simple, correct Python build frontend." in captured.out
|
assert "A simple, correct Python build frontend." in captured.out
|
||||||
|
|||||||
+11
-9
@@ -6,12 +6,12 @@ from . import test_projects, utils
|
|||||||
|
|
||||||
project_with_skip_asserts = test_projects.new_c_project(
|
project_with_skip_asserts = test_projects.new_c_project(
|
||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
r"""
|
rf"""
|
||||||
# explode if run on PyPyor Python 3.7 (these should be skipped)
|
|
||||||
if sys.implementation.name != "cpython":
|
if sys.implementation.name != "cpython":
|
||||||
raise Exception("Only CPython shall be built")
|
raise Exception("Only CPython shall be built")
|
||||||
if sys.version_info[0:2] == (3, 7):
|
expected_version = {"({}, {})".format(*utils.SINGLE_PYTHON_VERSION)}
|
||||||
raise Exception("CPython 3.7 should be skipped")
|
if sys.version_info[0:2] != expected_version:
|
||||||
|
raise Exception("CPython {{}}.{{}} should be skipped".format(*sys.version_info[0:2]))
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -21,17 +21,19 @@ def test(tmp_path):
|
|||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
project_with_skip_asserts.generate(project_dir)
|
project_with_skip_asserts.generate(project_dir)
|
||||||
|
|
||||||
|
skip = " ".join(
|
||||||
|
f"cp3{minor}-*" for minor in range(6, 30) if (3, minor) != utils.SINGLE_PYTHON_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp3*-*",
|
"CIBW_BUILD": "cp3*-*",
|
||||||
"CIBW_SKIP": "cp37-*",
|
"CIBW_SKIP": f"*t-* {skip}",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that we got the right wheels. There should be no PyPy or 3.7.
|
# check that we got the right wheels. There should be a single version of CPython.
|
||||||
expected_wheels = [
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
w for w in utils.expected_wheels("spam", "0.1.0") if ("-cp3" in w) and ("-cp37" not in w)
|
|
||||||
]
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
@@ -21,17 +21,16 @@ def test_podman(tmp_path, capfd, request):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp310-*{manylinux,musllinux}_x86_64",
|
"CIBW_ARCHS": "x86_64",
|
||||||
"CIBW_BEFORE_ALL": "echo 'test log statement from before-all'",
|
"CIBW_BEFORE_ALL": "echo 'test log statement from before-all'",
|
||||||
"CIBW_CONTAINER_ENGINE": "podman",
|
"CIBW_CONTAINER_ENGINE": "podman",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [
|
expected_wheels = [
|
||||||
w
|
w for w in utils.expected_wheels("spam", "0.1.0", single_python=True) if "x86_64" in w
|
||||||
for w in utils.expected_wheels("spam", "0.1.0")
|
|
||||||
if ("-cp310-" in w) and ("x86_64" in w) and ("manylinux" in w or "musllinux" in w)
|
|
||||||
]
|
]
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
@@ -51,15 +50,16 @@ def test_create_args(tmp_path, capfd):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp310-manylinux_*",
|
"CIBW_SKIP": "*-musllinux_*",
|
||||||
"CIBW_BEFORE_ALL": "echo TEST_CREATE_ARGS is set to $TEST_CREATE_ARGS",
|
"CIBW_BEFORE_ALL": "echo TEST_CREATE_ARGS is set to $TEST_CREATE_ARGS",
|
||||||
"CIBW_CONTAINER_ENGINE": "docker; create_args: --env=TEST_CREATE_ARGS=itworks",
|
"CIBW_CONTAINER_ENGINE": "docker; create_args: --env=TEST_CREATE_ARGS=itworks",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_wheels = [
|
expected_wheels = utils.expected_wheels(
|
||||||
w for w in utils.expected_wheels("spam", "0.1.0") if ("cp310-manylinux" in w)
|
"spam", "0.1.0", musllinux_versions=[], single_python=True
|
||||||
]
|
)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
|
|||||||
+27
-41
@@ -56,76 +56,62 @@ PyMODINIT_FUNC PyInit_spam(void)
|
|||||||
cpp_test_project.files["setup.py"] = jinja2.Template(setup_py_template)
|
cpp_test_project.files["setup.py"] = jinja2.Template(setup_py_template)
|
||||||
cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template)
|
cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template)
|
||||||
|
|
||||||
cpp11_project = cpp_test_project.copy()
|
|
||||||
cpp11_project.template_context["extra_compile_args"] = (
|
|
||||||
["/std:c++11"] if utils.platform == "windows" else ["-std=c++11"]
|
|
||||||
)
|
|
||||||
cpp11_project.template_context["spam_cpp_top_level_add"] = "#include <array>"
|
|
||||||
|
|
||||||
|
|
||||||
def test_cpp11(tmp_path):
|
def test_cpp11(tmp_path):
|
||||||
# This test checks that the C++11 standard is supported
|
# This test checks that the C++11 standard is supported
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
|
cpp11_project = cpp_test_project.copy()
|
||||||
|
cpp11_project.template_context["extra_compile_args"] = (
|
||||||
|
["/std:c++11"] if utils.platform == "windows" else ["-std=c++11"]
|
||||||
|
)
|
||||||
|
cpp11_project.template_context["spam_cpp_top_level_add"] = "#include <array>"
|
||||||
cpp11_project.generate(project_dir)
|
cpp11_project.generate(project_dir)
|
||||||
|
|
||||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
actual_wheels = utils.cibuildwheel_run(project_dir, single_python=True)
|
||||||
expected_wheels = list(utils.expected_wheels("spam", "0.1.0"))
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
cpp14_project = cpp_test_project.copy()
|
|
||||||
cpp14_project.template_context["extra_compile_args"] = (
|
|
||||||
["/std:c++14"] if utils.platform == "windows" else ["-std=c++14"]
|
|
||||||
)
|
|
||||||
cpp14_project.template_context["spam_cpp_top_level_add"] = "int a = 100'000;"
|
|
||||||
|
|
||||||
|
|
||||||
def test_cpp14(tmp_path):
|
def test_cpp14(tmp_path):
|
||||||
# This test checks that the C++14 standard is supported
|
# This test checks that the C++14 standard is supported
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
|
cpp14_project = cpp_test_project.copy()
|
||||||
|
cpp14_project.template_context["extra_compile_args"] = (
|
||||||
|
["/std:c++14"] if utils.platform == "windows" else ["-std=c++14"]
|
||||||
|
)
|
||||||
|
cpp14_project.template_context["spam_cpp_top_level_add"] = "int a = 100'000;"
|
||||||
cpp14_project.generate(project_dir)
|
cpp14_project.generate(project_dir)
|
||||||
|
|
||||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
actual_wheels = utils.cibuildwheel_run(project_dir, single_python=True)
|
||||||
expected_wheels = list(utils.expected_wheels("spam", "0.1.0"))
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
cpp17_project = cpp_test_project.copy()
|
|
||||||
|
|
||||||
cpp17_project.template_context["extra_compile_args"] = [
|
|
||||||
"/std:c++17" if utils.platform == "windows" else "-std=c++17"
|
|
||||||
]
|
|
||||||
cpp17_project.template_context["spam_cpp_top_level_add"] = r"""
|
|
||||||
#include <utility>
|
|
||||||
auto a = std::pair(5.0, false);
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def test_cpp17(tmp_path):
|
def test_cpp17(tmp_path):
|
||||||
# This test checks that the C++17 standard is supported
|
# This test checks that the C++17 standard is supported
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
|
cpp17_project = cpp_test_project.copy()
|
||||||
|
cpp17_project.template_context["extra_compile_args"] = [
|
||||||
|
"/std:c++17" if utils.platform == "windows" else "-std=c++17"
|
||||||
|
]
|
||||||
|
cpp17_project.template_context["spam_cpp_top_level_add"] = r"""
|
||||||
|
#include <utility>
|
||||||
|
auto a = std::pair(5.0, false);
|
||||||
|
"""
|
||||||
cpp17_project.generate(project_dir)
|
cpp17_project.generate(project_dir)
|
||||||
|
|
||||||
if os.environ.get("APPVEYOR_BUILD_WORKER_IMAGE", "") == "Visual Studio 2015":
|
if os.environ.get("APPVEYOR_BUILD_WORKER_IMAGE", "") == "Visual Studio 2015":
|
||||||
pytest.skip("Visual Studio 2015 does not support C++17")
|
pytest.skip("Visual Studio 2015 does not support C++17")
|
||||||
|
|
||||||
# Pypy's distutils sets the default compiler to 'msvc9compiler', which
|
add_env = {}
|
||||||
# is too old to support cpp17.
|
|
||||||
add_env = {"CIBW_SKIP": "pp*"}
|
|
||||||
|
|
||||||
if utils.platform == "macos":
|
if utils.platform == "macos":
|
||||||
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.13"
|
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.13"
|
||||||
|
|
||||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env, single_python=True)
|
||||||
expected_wheels = [
|
expected_wheels = utils.expected_wheels(
|
||||||
w
|
"spam", "0.1.0", macosx_deployment_target="10.13", single_python=True
|
||||||
for w in utils.expected_wheels("spam", "0.1.0", macosx_deployment_target="10.13")
|
)
|
||||||
if "-pp" not in w
|
|
||||||
]
|
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from test import test_projects
|
from contextlib import nullcontext as does_not_raise
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from test import test_projects
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
basic_project = test_projects.new_c_project()
|
basic_project = test_projects.new_c_project()
|
||||||
@@ -30,8 +32,14 @@ def test(tmp_path, capfd):
|
|||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
basic_project.generate(project_dir)
|
basic_project.generate(project_dir)
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError):
|
num_builds = len(utils.cibuildwheel_get_build_identifiers(project_dir))
|
||||||
utils.cibuildwheel_run(
|
if num_builds > 1:
|
||||||
|
expectation = pytest.raises(subprocess.CalledProcessError)
|
||||||
|
else:
|
||||||
|
expectation = does_not_raise()
|
||||||
|
|
||||||
|
with expectation as exc_info:
|
||||||
|
result = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_REPAIR_WHEEL_COMMAND": "python repair.py {wheel} {dest_dir}",
|
"CIBW_REPAIR_WHEEL_COMMAND": "python repair.py {wheel} {dest_dir}",
|
||||||
@@ -39,4 +47,15 @@ def test(tmp_path, capfd):
|
|||||||
)
|
)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
assert "Build failed because a wheel named" in captured.err
|
if num_builds > 1:
|
||||||
|
assert "Build failed because a wheel named" in captured.err
|
||||||
|
assert exc_info.value.returncode == 6
|
||||||
|
else:
|
||||||
|
# We only produced one wheel (currently Pyodide)
|
||||||
|
# check that it has the right name
|
||||||
|
#
|
||||||
|
# As far as I can tell, this is the only full test coverage for
|
||||||
|
# CIBW_REPAIR_WHEEL_COMMAND so this is useful even in the case when no
|
||||||
|
# error is raised
|
||||||
|
assert "spam-0.1.0-py2-none-pyodide" in captured.out
|
||||||
|
assert result[0].startswith("spam-0.1.0-py2-none-")
|
||||||
@@ -52,12 +52,14 @@ def get_versions_from_constraint_file(constraint_file):
|
|||||||
return dict(re.findall(VERSION_REGEX, constraint_file_text))
|
return dict(re.findall(VERSION_REGEX, constraint_file_text))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("python_version", ["3.6", "3.8", "3.10"])
|
@pytest.mark.parametrize("python_version", ["3.6", "3.8", "3.12"])
|
||||||
def test_pinned_versions(tmp_path, python_version, build_frontend_env):
|
def test_pinned_versions(tmp_path, python_version, build_frontend_env_nouv):
|
||||||
if utils.platform == "linux":
|
if utils.platform == "linux":
|
||||||
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
||||||
if python_version == "3.6" and utils.platform == "macos" and platform.machine() == "arm64":
|
if python_version == "3.6" and utils.platform == "macos" and platform.machine() == "arm64":
|
||||||
pytest.skip("macOS arm64 does not support Python 3.6")
|
pytest.skip("macOS arm64 does not support Python 3.6")
|
||||||
|
if python_version != "3.12" and utils.platform == "pyodide":
|
||||||
|
pytest.skip(f"pyodide does not support Python {python_version}")
|
||||||
|
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
project_with_expected_version_checks.generate(project_dir)
|
project_with_expected_version_checks.generate(project_dir)
|
||||||
@@ -79,7 +81,7 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env):
|
|||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": build_pattern,
|
"CIBW_BUILD": build_pattern,
|
||||||
"CIBW_ENVIRONMENT": cibw_environment_option,
|
"CIBW_ENVIRONMENT": cibw_environment_option,
|
||||||
**build_frontend_env,
|
**build_frontend_env_nouv,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -93,7 +95,7 @@ def test_pinned_versions(tmp_path, python_version, build_frontend_env):
|
|||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
def test_dependency_constraints_file(tmp_path, build_frontend_env):
|
def test_dependency_constraints_file(tmp_path, build_frontend_env_nouv):
|
||||||
if utils.platform == "linux":
|
if utils.platform == "linux":
|
||||||
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
||||||
|
|
||||||
@@ -111,7 +113,6 @@ def test_dependency_constraints_file(tmp_path, build_frontend_env):
|
|||||||
"""
|
"""
|
||||||
pip=={pip}
|
pip=={pip}
|
||||||
delocate=={delocate}
|
delocate=={delocate}
|
||||||
importlib-metadata<3,>=0.12; python_version < "3.8"
|
|
||||||
""".format(**tool_versions)
|
""".format(**tool_versions)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -131,7 +132,7 @@ def test_dependency_constraints_file(tmp_path, build_frontend_env):
|
|||||||
"CIBW_ENVIRONMENT": cibw_environment_option,
|
"CIBW_ENVIRONMENT": cibw_environment_option,
|
||||||
"CIBW_DEPENDENCY_VERSIONS": str(constraints_file),
|
"CIBW_DEPENDENCY_VERSIONS": str(constraints_file),
|
||||||
"CIBW_SKIP": "cp36-*",
|
"CIBW_SKIP": "cp36-*",
|
||||||
**build_frontend_env,
|
**build_frontend_env_nouv,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from cibuildwheel.util import CIBW_CACHE_PATH, CIProvider, detect_ci_provider
|
||||||
|
|
||||||
|
from . import test_projects, utils
|
||||||
|
|
||||||
|
basic_project = test_projects.new_c_project()
|
||||||
|
basic_project.files["check_node.py"] = r"""
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
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
|
||||||
|
cibw_cache_path = Path(sys.argv[1]).resolve(strict=True)
|
||||||
|
# find the node executable in PATH
|
||||||
|
node = shutil.which("node")
|
||||||
|
assert node is not None, "node is None"
|
||||||
|
node_path = Path(node).resolve(strict=True)
|
||||||
|
# it shall be in cibuildwheel cache
|
||||||
|
assert cibw_cache_path in node_path.parents, f"{cibw_cache_path} not a parent of {node_path}"
|
||||||
|
# find the path to the node executable that runs pyodide
|
||||||
|
node_js = run_js("globalThis.process.execPath")
|
||||||
|
assert node_js is not None, "node_js is None"
|
||||||
|
node_js_path = Path(node_js).resolve(strict=True)
|
||||||
|
# it shall be the one pinned by cibuildwheel
|
||||||
|
assert node_js_path == node_path, f"{node_js_path} != {node_path}"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
check_node()
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("use_pyproject_toml", [True, False])
|
||||||
|
def test_pyodide_build(tmp_path, use_pyproject_toml):
|
||||||
|
if sys.platform == "win32":
|
||||||
|
pytest.skip("emsdk doesn't work correctly on Windows")
|
||||||
|
|
||||||
|
if not shutil.which("python3.12"):
|
||||||
|
pytest.skip("Python 3.12 not installed")
|
||||||
|
|
||||||
|
if detect_ci_provider() == CIProvider.travis_ci:
|
||||||
|
pytest.skip("Python 3.12 is just a non-working pyenv shim")
|
||||||
|
|
||||||
|
if use_pyproject_toml:
|
||||||
|
basic_project.files["pyproject.toml"] = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
project_dir = tmp_path / "project"
|
||||||
|
basic_project.generate(project_dir)
|
||||||
|
|
||||||
|
# check for node in 1 case only to reduce CI load
|
||||||
|
add_env = {}
|
||||||
|
if use_pyproject_toml:
|
||||||
|
add_env["CIBW_TEST_COMMAND"] = f"python {{project}}/check_node.py {CIBW_CACHE_PATH}"
|
||||||
|
|
||||||
|
# build the wheels
|
||||||
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
|
project_dir,
|
||||||
|
add_args=["--platform", "pyodide"],
|
||||||
|
add_env=add_env,
|
||||||
|
)
|
||||||
|
|
||||||
|
# check that the expected wheels are produced
|
||||||
|
expected_wheels = [
|
||||||
|
"spam-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl",
|
||||||
|
]
|
||||||
|
|
||||||
|
print("actual_wheels", actual_wheels)
|
||||||
|
print("expected_wheels", expected_wheels)
|
||||||
|
|
||||||
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
+10
-6
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import itertools
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -18,9 +19,13 @@ def test_spam():
|
|||||||
|
|
||||||
|
|
||||||
def test(tmp_path, request):
|
def test(tmp_path, request):
|
||||||
if not request.config.getoption("--run-emulation"):
|
archs = request.config.getoption("--run-emulation")
|
||||||
|
if archs is None:
|
||||||
pytest.skip("needs --run-emulation option to run")
|
pytest.skip("needs --run-emulation option to run")
|
||||||
|
|
||||||
|
if archs == "all":
|
||||||
|
archs = " ".join(utils.EMULATED_ARCHS)
|
||||||
|
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
project_with_a_test.generate(project_dir)
|
project_with_a_test.generate(project_dir)
|
||||||
|
|
||||||
@@ -30,15 +35,14 @@ def test(tmp_path, request):
|
|||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
"CIBW_TEST_COMMAND": "pytest {project}/test",
|
"CIBW_TEST_COMMAND": "pytest {project}/test",
|
||||||
"CIBW_ARCHS": "aarch64 ppc64le s390x",
|
"CIBW_ARCHS": archs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# also check that we got the right wheels
|
# also check that we got the right wheels
|
||||||
expected_wheels = (
|
expected_wheels = itertools.chain.from_iterable(
|
||||||
utils.expected_wheels("spam", "0.1.0", machine_arch="aarch64")
|
utils.expected_wheels("spam", "0.1.0", machine_arch=arch, single_arch=True)
|
||||||
+ utils.expected_wheels("spam", "0.1.0", machine_arch="ppc64le")
|
for arch in archs.split(" ")
|
||||||
+ utils.expected_wheels("spam", "0.1.0", machine_arch="s390x")
|
|
||||||
)
|
)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|||||||
@@ -49,10 +49,11 @@ def test(tmp_path):
|
|||||||
"CIBW_ENVIRONMENT": """CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path""",
|
"CIBW_ENVIRONMENT": """CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path""",
|
||||||
"CIBW_ENVIRONMENT_WINDOWS": f'''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$({python_echo} 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''',
|
"CIBW_ENVIRONMENT_WINDOWS": f'''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$({python_echo} 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''',
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# also check that we got the right wheels built
|
# also check that we got the right wheels built
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -92,10 +93,18 @@ def test_overridden_path(tmp_path, capfd):
|
|||||||
|
|
||||||
assert len(os.listdir(output_dir)) == 0
|
assert len(os.listdir(output_dir)) == 0
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
assert "python available on PATH doesn't match our installed instance" in captured.err
|
assert "python available on PATH doesn't match our installed instance" in captured.err.replace(
|
||||||
|
"venv", "installed"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("build_frontend", ["pip", "build"])
|
@pytest.mark.parametrize(
|
||||||
|
"build_frontend",
|
||||||
|
[
|
||||||
|
pytest.param("pip", marks=utils.skip_if_pyodide("No pip for pyodide")),
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_overridden_pip_constraint(tmp_path, build_frontend):
|
def test_overridden_pip_constraint(tmp_path, build_frontend):
|
||||||
"""
|
"""
|
||||||
Verify that users can use PIP_CONSTRAINT to specify a specific version of
|
Verify that users can use PIP_CONSTRAINT to specify a specific version of
|
||||||
@@ -108,7 +117,7 @@ def test_overridden_pip_constraint(tmp_path, build_frontend):
|
|||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
import pytz
|
import pytz
|
||||||
assert pytz.__version__ == "2022.4"
|
assert pytz.__version__ == "2022.4", f"{pytz.__version__!r} != '2022.4'"
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -133,12 +142,12 @@ def test_overridden_pip_constraint(tmp_path, build_frontend):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp312-*",
|
|
||||||
"CIBW_BUILD_FRONTEND": build_frontend,
|
"CIBW_BUILD_FRONTEND": build_frontend,
|
||||||
"PIP_CONSTRAINT": str(constraints_file),
|
"PIP_CONSTRAINT": str(constraints_file),
|
||||||
"CIBW_ENVIRONMENT_LINUX": "PIP_CONSTRAINT=./constraints.txt",
|
"CIBW_ENVIRONMENT_LINUX": "PIP_CONSTRAINT=./constraints.txt",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp312" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
+11
-21
@@ -6,6 +6,7 @@ import sys
|
|||||||
import textwrap
|
import textwrap
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
from test.test_projects.base import TestProject
|
from test.test_projects.base import TestProject
|
||||||
|
|
||||||
from . import test_projects, utils
|
from . import test_projects, utils
|
||||||
@@ -33,6 +34,8 @@ def cibuildwheel_from_sdist_run(sdist_path, add_env=None, config_file=None):
|
|||||||
if add_env:
|
if add_env:
|
||||||
env.update(add_env)
|
env.update(add_env)
|
||||||
|
|
||||||
|
env["CIBW_BUILD"] = "cp{}{}-*".format(*utils.SINGLE_PYTHON_VERSION)
|
||||||
|
|
||||||
with TemporaryDirectory() as tmp_output_dir:
|
with TemporaryDirectory() as tmp_output_dir:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
@@ -73,15 +76,11 @@ def test_simple(tmp_path):
|
|||||||
|
|
||||||
# build the wheels from sdist
|
# build the wheels from sdist
|
||||||
actual_wheels = cibuildwheel_from_sdist_run(
|
actual_wheels = cibuildwheel_from_sdist_run(
|
||||||
sdist_path,
|
sdist_path, add_env={"CIBW_BEFORE_BUILD": setup_py_assertion_cmd}
|
||||||
add_env={
|
|
||||||
"CIBW_BEFORE_BUILD": setup_py_assertion_cmd,
|
|
||||||
"CIBW_BUILD": "cp39-*",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp39" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -105,14 +104,10 @@ def test_external_config_file_argument(tmp_path, capfd):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# build the wheels from sdist
|
# build the wheels from sdist
|
||||||
actual_wheels = cibuildwheel_from_sdist_run(
|
actual_wheels = cibuildwheel_from_sdist_run(sdist_path, config_file=str(config_file))
|
||||||
sdist_path,
|
|
||||||
add_env={"CIBW_BUILD": "cp39-*"},
|
|
||||||
config_file=str(config_file),
|
|
||||||
)
|
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp39" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
# check that before-all was run
|
# check that before-all was run
|
||||||
@@ -136,13 +131,10 @@ def test_config_in_pyproject_toml(tmp_path, capfd):
|
|||||||
sdist_path = make_sdist(project, sdist_dir)
|
sdist_path = make_sdist(project, sdist_dir)
|
||||||
|
|
||||||
# build the wheels from sdist
|
# build the wheels from sdist
|
||||||
actual_wheels = cibuildwheel_from_sdist_run(
|
actual_wheels = cibuildwheel_from_sdist_run(sdist_path)
|
||||||
sdist_path,
|
|
||||||
add_env={"CIBW_BUILD": "cp39-*"},
|
|
||||||
)
|
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp39" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
# check that before-build was run
|
# check that before-build was run
|
||||||
@@ -174,13 +166,11 @@ def test_internal_config_file_argument(tmp_path, capfd):
|
|||||||
|
|
||||||
# build the wheels from sdist, referencing the config file inside
|
# build the wheels from sdist, referencing the config file inside
|
||||||
actual_wheels = cibuildwheel_from_sdist_run(
|
actual_wheels = cibuildwheel_from_sdist_run(
|
||||||
sdist_path,
|
sdist_path, config_file="{package}/wheel_build_config.toml"
|
||||||
add_env={"CIBW_BUILD": "cp39-*"},
|
|
||||||
config_file="{package}/wheel_build_config.toml",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp39" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
# check that before-all was run
|
# check that before-all was run
|
||||||
|
|||||||
+25
-22
@@ -14,7 +14,7 @@ ALL_MACOS_WHEELS = {
|
|||||||
*utils.expected_wheels("spam", "0.1.0", machine_arch="arm64", include_universal2=True),
|
*utils.expected_wheels("spam", "0.1.0", machine_arch="arm64", include_universal2=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
DEPLOYMENT_TARGET_TOO_LOW_WARNING = "[WARNING] MACOSX_DEPLOYMENT_TARGET is set to a lower value"
|
DEPLOYMENT_TARGET_TOO_LOW_WARNING = "Bumping MACOSX_DEPLOYMENT_TARGET"
|
||||||
|
|
||||||
|
|
||||||
def get_xcode_version() -> tuple[int, int]:
|
def get_xcode_version() -> tuple[int, int]:
|
||||||
@@ -42,13 +42,11 @@ def test_cross_compiled_build(tmp_path):
|
|||||||
|
|
||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={"CIBW_ARCHS": "x86_64, universal2, arm64"},
|
||||||
"CIBW_BUILD": "cp39-*",
|
single_python=True,
|
||||||
"CIBW_ARCHS": "x86_64, universal2, arm64",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
|
||||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w]
|
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w]
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ def test_cross_compiled_test(tmp_path, capfd, build_universal2):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp39-*" if build_universal2 else "*p39-*",
|
"CIBW_BUILD": "cp310-*" if build_universal2 else "*p310-*",
|
||||||
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
||||||
"CIBW_ARCHS": "universal2" if build_universal2 else "x86_64 arm64",
|
"CIBW_ARCHS": "universal2" if build_universal2 else "x86_64 arm64",
|
||||||
"CIBW_BUILD_VERBOSITY": "3",
|
"CIBW_BUILD_VERBOSITY": "3",
|
||||||
@@ -103,11 +101,11 @@ def test_cross_compiled_test(tmp_path, capfd, build_universal2):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if build_universal2:
|
if build_universal2:
|
||||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" in w]
|
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp310" in w and "universal2" in w]
|
||||||
else:
|
else:
|
||||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "p39-" in w and "universal2" not in w]
|
expected_wheels = [w for w in ALL_MACOS_WHEELS if "p310-" in w and "universal2" not in w]
|
||||||
if platform_machine == "x86_64":
|
if platform_machine == "x86_64":
|
||||||
expected_wheels = [w for w in expected_wheels if not ("pp39" in w and "arm64" in w)]
|
expected_wheels = [w for w in expected_wheels if not ("pp310" in w and "arm64" in w)]
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
@@ -123,11 +121,11 @@ def test_deployment_target_warning_is_firing(tmp_path, capfd):
|
|||||||
utils.cibuildwheel_run(
|
utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp39-*",
|
|
||||||
"CIBW_ARCHS": "x86_64",
|
"CIBW_ARCHS": "x86_64",
|
||||||
"MACOSX_DEPLOYMENT_TARGET": "10.8",
|
"MACOSX_DEPLOYMENT_TARGET": "10.8",
|
||||||
"CIBW_BUILD_VERBOSITY": "3",
|
"CIBW_BUILD_VERBOSITY": "3",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
@@ -149,11 +147,11 @@ def test_universal2_testing_on_x86_64(tmp_path, capfd, skip_arm64_test):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp39-*",
|
|
||||||
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
||||||
"CIBW_ARCHS": "universal2",
|
"CIBW_ARCHS": "universal2",
|
||||||
"CIBW_TEST_SKIP": "*_universal2:arm64" if skip_arm64_test else "",
|
"CIBW_TEST_SKIP": "*_universal2:arm64" if skip_arm64_test else "",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
@@ -168,12 +166,13 @@ def test_universal2_testing_on_x86_64(tmp_path, capfd, skip_arm64_test):
|
|||||||
else:
|
else:
|
||||||
assert warning_message in captured.err
|
assert warning_message in captured.err
|
||||||
|
|
||||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" in w]
|
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
|
||||||
|
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w]
|
||||||
|
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
def test_universal2_testing_on_arm64(tmp_path, capfd):
|
def test_universal2_testing_on_arm64(build_frontend_env, tmp_path, capfd):
|
||||||
# cibuildwheel should test the universal2 wheel on both x86_64 and arm64, when run on arm64
|
# cibuildwheel should test the universal2 wheel on both x86_64 and arm64, when run on arm64
|
||||||
if utils.platform != "macos":
|
if utils.platform != "macos":
|
||||||
pytest.skip("this test is only relevant to macos")
|
pytest.skip("this test is only relevant to macos")
|
||||||
@@ -186,29 +185,33 @@ def test_universal2_testing_on_arm64(tmp_path, capfd):
|
|||||||
actual_wheels = utils.cibuildwheel_run(
|
actual_wheels = utils.cibuildwheel_run(
|
||||||
project_dir,
|
project_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_BUILD": "cp39-*",
|
|
||||||
"CIBW_ARCHS": "universal2",
|
"CIBW_ARCHS": "universal2",
|
||||||
# check that a native dependency is correctly installed, once per each testing arch
|
# check that a native dependency is correctly installed, once per each testing arch
|
||||||
"CIBW_TEST_REQUIRES": "numpy",
|
"CIBW_TEST_REQUIRES": "--only-binary :all: pillow>=10.3", # pillow>=10.3 provides wheels for macOS 10.10, not 10.9
|
||||||
"CIBW_TEST_COMMAND": '''python -c "import numpy, platform; print(f'running tests on {platform.machine()} with numpy {numpy.__version__}')"''',
|
"CIBW_TEST_COMMAND": '''python -c "import PIL, platform; print(f'running tests on {platform.machine()} with pillow {PIL.__version__}')"''',
|
||||||
|
**build_frontend_env,
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
assert "running tests on arm64" in captured.out
|
assert "running tests on arm64 with pillow" in captured.out
|
||||||
assert "running tests on x86_64" in captured.out
|
assert "running tests on x86_64 with pillow" in captured.out
|
||||||
|
|
||||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" in w]
|
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
|
||||||
|
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w]
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
def test_cp38_arm64_testing(tmp_path, capfd):
|
def test_cp38_arm64_testing(tmp_path, capfd, request):
|
||||||
if utils.platform != "macos":
|
if utils.platform != "macos":
|
||||||
pytest.skip("this test is only relevant to macos")
|
pytest.skip("this test is only relevant to macos")
|
||||||
if get_xcode_version() < (12, 2):
|
if get_xcode_version() < (12, 2):
|
||||||
pytest.skip("this test only works with Xcode 12.2 or greater")
|
pytest.skip("this test only works with Xcode 12.2 or greater")
|
||||||
if platform.machine() != "arm64":
|
if platform.machine() != "arm64":
|
||||||
pytest.skip("this test only works on arm64")
|
pytest.skip("this test only works on arm64")
|
||||||
|
if request.config.getoption("--run-cp38-universal2"):
|
||||||
|
pytest.skip("--run-cp38-universal2 option skips this test")
|
||||||
|
|
||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
basic_project.generate(project_dir)
|
basic_project.generate(project_dir)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ def test(musllinux_image, tmp_path):
|
|||||||
|
|
||||||
# build the wheels
|
# build the wheels
|
||||||
add_env = {
|
add_env = {
|
||||||
"CIBW_BUILD": "*-musllinux*",
|
"CIBW_SKIP": "*-manylinux*",
|
||||||
"CIBW_MUSLLINUX_X86_64_IMAGE": musllinux_image,
|
"CIBW_MUSLLINUX_X86_64_IMAGE": musllinux_image,
|
||||||
"CIBW_MUSLLINUX_I686_IMAGE": musllinux_image,
|
"CIBW_MUSLLINUX_I686_IMAGE": musllinux_image,
|
||||||
"CIBW_MUSLLINUX_AARCH64_IMAGE": musllinux_image,
|
"CIBW_MUSLLINUX_AARCH64_IMAGE": musllinux_image,
|
||||||
@@ -46,11 +46,12 @@ def test(musllinux_image, tmp_path):
|
|||||||
"CIBW_MUSLLINUX_S390X_IMAGE": musllinux_image,
|
"CIBW_MUSLLINUX_S390X_IMAGE": musllinux_image,
|
||||||
}
|
}
|
||||||
|
|
||||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env, single_python=True)
|
||||||
expected_wheels = utils.expected_wheels(
|
expected_wheels = utils.expected_wheels(
|
||||||
"spam",
|
"spam",
|
||||||
"0.1.0",
|
"0.1.0",
|
||||||
manylinux_versions=[],
|
manylinux_versions=[],
|
||||||
musllinux_versions=[musllinux_image],
|
musllinux_versions=[musllinux_image],
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|||||||
+3
-4
@@ -8,8 +8,8 @@ basic_project = test_projects.new_c_project(
|
|||||||
setup_py_add=textwrap.dedent(
|
setup_py_add=textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
# Will fail if PEP 518 does work
|
# Will fail if PEP 518 does work
|
||||||
import requests
|
import jmespath
|
||||||
assert requests.__version__ == "2.27.0", "Requests found but wrong version ({0})".format(requests.__version__)
|
assert jmespath.__version__ == "0.10.0", "'jmespath' found but wrong version ({0})".format(jmespath.__version__)
|
||||||
|
|
||||||
# Just making sure environment is still set
|
# Just making sure environment is still set
|
||||||
import os
|
import os
|
||||||
@@ -24,8 +24,7 @@ basic_project.files["pyproject.toml"] = """
|
|||||||
requires = [
|
requires = [
|
||||||
"setuptools >= 42",
|
"setuptools >= 42",
|
||||||
"setuptools_scm[toml]>=4.1.2",
|
"setuptools_scm[toml]>=4.1.2",
|
||||||
"wheel",
|
"jmespath==0.10.0"
|
||||||
"requests==2.27.0"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|||||||
@@ -42,15 +42,20 @@ PyMODINIT_FUNC PyInit_spam(void)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
SETUP_PY_TEMPLATE = r"""
|
SETUP_PY_TEMPLATE = r"""
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from setuptools import setup, Extension
|
from setuptools import setup, Extension
|
||||||
|
|
||||||
{{ setup_py_add }}
|
{{ setup_py_add }}
|
||||||
|
|
||||||
libraries = []
|
libraries = []
|
||||||
if sys.platform.startswith('linux'):
|
# Emscripten fails if you pass -lc...
|
||||||
|
# See: https://github.com/emscripten-core/emscripten/issues/16680
|
||||||
|
if sys.platform.startswith('linux') and "emscripten" not in os.environ.get("_PYTHON_HOST_PLATFORM", ""):
|
||||||
libraries.extend(['m', 'c'])
|
libraries.extend(['m', 'c'])
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
ext_modules=[Extension(
|
ext_modules=[Extension(
|
||||||
'spam',
|
'spam',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from test import test_projects
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from test import test_projects
|
||||||
|
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
pure_python_project = test_projects.TestProject()
|
pure_python_project = test_projects.TestProject()
|
||||||
@@ -30,10 +31,11 @@ def test(tmp_path, capfd):
|
|||||||
project_dir = tmp_path / "project"
|
project_dir = tmp_path / "project"
|
||||||
pure_python_project.generate(project_dir)
|
pure_python_project.generate(project_dir)
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError):
|
with pytest.raises(subprocess.CalledProcessError) as exc_info:
|
||||||
print("produced wheels:", utils.cibuildwheel_run(project_dir))
|
print("produced wheels:", utils.cibuildwheel_run(project_dir))
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
print("out", captured.out)
|
print("out", captured.out)
|
||||||
print("err", captured.err)
|
print("err", captured.err)
|
||||||
|
assert exc_info.value.returncode == 5
|
||||||
assert "Build failed because a pure Python wheel was generated" in captured.err
|
assert "Build failed because a pure Python wheel was generated" in captured.err
|
||||||
|
|||||||
@@ -45,13 +45,12 @@ def test(capfd, tmp_path):
|
|||||||
add_env={
|
add_env={
|
||||||
"CIBW_BEFORE_BUILD": "python {project}/bin/before_build.py",
|
"CIBW_BEFORE_BUILD": "python {project}/bin/before_build.py",
|
||||||
"CIBW_TEST_COMMAND": "python {package}/test/run_tests.py",
|
"CIBW_TEST_COMMAND": "python {package}/test/run_tests.py",
|
||||||
# this shouldn't depend on the version of python, so build only CPython 3.10
|
|
||||||
"CIBW_BUILD": "cp310-*",
|
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# check that the expected wheels are produced
|
# check that the expected wheels are produced
|
||||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp310" in w]
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
captured = capfd.readouterr()
|
captured = capfd.readouterr()
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class TestSpam(TestCase):
|
|||||||
|
|
||||||
self.assertTrue(path_contains(sys.prefix, sys.executable))
|
self.assertTrue(path_contains(sys.prefix, sys.executable))
|
||||||
self.assertTrue(path_contains(sys.prefix, spam.__file__))
|
self.assertTrue(path_contains(sys.prefix, spam.__file__))
|
||||||
|
self.assertIn("VIRTUAL_ENV", os.environ)
|
||||||
|
|
||||||
def test_uname(self):
|
def test_uname(self):
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
@@ -66,7 +67,7 @@ class TestSpam(TestCase):
|
|||||||
# See #336 for more info.
|
# See #336 for more info.
|
||||||
bits = struct.calcsize("P") * 8
|
bits = struct.calcsize("P") * 8
|
||||||
if bits == 32:
|
if bits == 32:
|
||||||
self.assertEqual(platform.machine(), "i686")
|
self.assertIn(platform.machine(), ["i686", "wasm32"])
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ def test(tmp_path):
|
|||||||
"CIBW_TEST_REQUIRES": "pytest",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": "false || pytest {project}/test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
|
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -102,13 +103,14 @@ def test_extras_require(tmp_path):
|
|||||||
"CIBW_TEST_EXTRAS": "test",
|
"CIBW_TEST_EXTRAS": "test",
|
||||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||||
# mac/linux.
|
# mac/linux.
|
||||||
"CIBW_TEST_COMMAND": "false || pytest {project}/test",
|
"CIBW_TEST_COMMAND": f"false || {utils.invoke_pytest()} {{project}}/test",
|
||||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
|
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || pytest {project}/test",
|
||||||
},
|
},
|
||||||
|
single_python=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# also check that we got the right wheels
|
# also check that we got the right wheels
|
||||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True)
|
||||||
assert set(actual_wheels) == set(expected_wheels)
|
assert set(actual_wheels) == set(expected_wheels)
|
||||||
|
|
||||||
|
|
||||||
@@ -133,8 +135,8 @@ def test_failing_test(tmp_path):
|
|||||||
project_dir,
|
project_dir,
|
||||||
output_dir=output_dir,
|
output_dir=output_dir,
|
||||||
add_env={
|
add_env={
|
||||||
"CIBW_TEST_REQUIRES": "nose",
|
"CIBW_TEST_REQUIRES": "pytest",
|
||||||
"CIBW_TEST_COMMAND": "nosetests {project}/test",
|
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} {{project}}/test",
|
||||||
# manylinux1 has a version of bash that's been shown to have
|
# manylinux1 has a version of bash that's been shown to have
|
||||||
# problems with this, so let's check that.
|
# problems with this, so let's check that.
|
||||||
"CIBW_MANYLINUX_I686_IMAGE": "manylinux1",
|
"CIBW_MANYLINUX_I686_IMAGE": "manylinux1",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user