Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b0dd3287 | ||
|
|
0787a44d99 | ||
|
|
fd11286290 | ||
|
|
22dc864d60 | ||
|
|
9d2f46ce4e | ||
|
|
b1ed7bb3bc | ||
|
|
ca08f5fbcf | ||
|
|
229029e112 | ||
|
|
3294577c17 | ||
|
|
8f51efbc3e | ||
|
|
ebdbb3cbd5 | ||
|
|
3a30bec9ef | ||
|
|
126b81916d | ||
|
|
9abea5b73b | ||
|
|
170e7aaeb9 | ||
|
|
5b570a2451 | ||
|
|
ffd7dddcc7 | ||
|
|
b0b13d3a16 | ||
|
|
b1781e4606 | ||
|
|
3580374b18 | ||
|
|
c6dd39bd83 | ||
|
|
dd8fe86308 | ||
|
|
2e12f05d5e |
@@ -4,6 +4,8 @@ set -o xtrace
|
||||
|
||||
if [ "$(uname -s)" == "Darwin" ]; then
|
||||
sudo softwareupdate --install-rosetta --agree-to-license
|
||||
else
|
||||
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
fi
|
||||
|
||||
$PYTHON --version
|
||||
|
||||
@@ -17,6 +17,7 @@ linux_x86_task:
|
||||
memory: 8G
|
||||
|
||||
install_pre_requirements_script:
|
||||
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
- apt install -y python3-venv python-is-python3
|
||||
<<: *RUN_TESTS
|
||||
|
||||
@@ -30,6 +31,7 @@ linux_aarch64_task:
|
||||
memory: 4G
|
||||
|
||||
install_pre_requirements_script:
|
||||
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
- apt install -y python3-venv python-is-python3
|
||||
<<: *RUN_TESTS
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Generate artifact attestation for sdist and wheel
|
||||
uses: actions/attest-build-provenance@5e9cb68e95676991667494a6a4e59b8a2f13e1d0 # v1.3.3
|
||||
uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3
|
||||
with:
|
||||
subject-path: "dist/cibuildwheel-*"
|
||||
|
||||
|
||||
@@ -52,17 +52,6 @@ jobs:
|
||||
|
||||
- uses: yezz123/setup-uv@v4
|
||||
|
||||
# Install podman on this CI instance for podman tests on linux
|
||||
# Snippet from: https://github.com/redhat-actions/podman-login/blob/main/.github/workflows/example.yml
|
||||
- name: Install latest podman
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
. /etc/os-release
|
||||
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
|
||||
curl -sSfL "https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key" | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install podman
|
||||
|
||||
# free some space to prevent reaching GHA disk space limits
|
||||
- name: Clean docker images
|
||||
if: runner.os == 'Linux'
|
||||
@@ -70,6 +59,11 @@ jobs:
|
||||
docker system prune -a -f
|
||||
df -h
|
||||
|
||||
# for oci_container unit tests
|
||||
- name: Set up QEMU
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
uv pip install --system ".[test]"
|
||||
@@ -168,10 +162,7 @@ jobs:
|
||||
run: python -m pip install ".[test,uv]"
|
||||
|
||||
- name: Set up QEMU
|
||||
id: qemu
|
||||
uses: docker/setup-qemu-action@v3
|
||||
with:
|
||||
platforms: all
|
||||
|
||||
- name: Run the emulation tests
|
||||
run: pytest --run-emulation ${{ matrix.arch }} test/test_emulation.py
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: github.ref == 'refs/heads/main' && github.repository == 'pypa/cibuildwheel'
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
commit-message: Update dependencies
|
||||
title: '[Bot] Update dependencies'
|
||||
|
||||
@@ -15,6 +15,7 @@ linux:
|
||||
PYTEST_ADDOPTS: -k "unit_test or test_0_basic" --suppress-no-test-exit-code
|
||||
script:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
- docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
- python -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||
- python ./bin/run_tests.py
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ repos:
|
||||
- id: trailing-whitespace
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.5.5
|
||||
rev: v0.6.4
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: ["--fix", "--show-fixes"]
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.11.0
|
||||
rev: v1.11.2
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy 3.8 on cibuildwheel/
|
||||
@@ -77,7 +77,7 @@ repos:
|
||||
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.29.1
|
||||
rev: 0.29.2
|
||||
hooks:
|
||||
- id: check-dependabot
|
||||
- id: check-github-actions
|
||||
|
||||
+14
-2
@@ -20,6 +20,14 @@ jobs:
|
||||
group: edge
|
||||
virt: vm
|
||||
env: PYTHON=python
|
||||
# docker is outdated in the arm64-graviton2 vm focal image (19.x)
|
||||
# we need to upgrade to get >= 24.0
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'deb https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable'
|
||||
packages:
|
||||
- docker-ce docker-ce-cli containerd.io
|
||||
|
||||
- name: Linux | ppc64le | Python 3.9
|
||||
python: 3.9
|
||||
@@ -44,11 +52,13 @@ jobs:
|
||||
python: 3.9
|
||||
services: docker
|
||||
arch: s390x
|
||||
allow_failure: True
|
||||
env: PYTHON=python
|
||||
|
||||
install:
|
||||
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all; fi
|
||||
- $PYTHON -m pip install -U pip
|
||||
- $PYTHON -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||
- $PYTHON -m pip install -e ".[test]" pytest-custom-exit-code
|
||||
|
||||
script: |
|
||||
# travis_wait disable the output while waiting
|
||||
@@ -56,5 +66,7 @@ script: |
|
||||
(while true; do echo "travis_keep_alive"; sleep 300; done) &
|
||||
SPINNER_PID=$!
|
||||
disown
|
||||
$PYTHON ./bin/run_tests.py --num-processes 2
|
||||
result=0
|
||||
$PYTHON ./bin/run_tests.py --num-processes 2 || result=1
|
||||
kill -9 ${SPINNER_PID}
|
||||
test ${result} -eq 0
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
This is a summary of the host Python versions and platforms covered by the different CI platforms:
|
||||
|
||||
| | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 |
|
||||
|---------|----------------------------------------------|-----------|-----------|---------|--------------------------------------|
|
||||
| Linux | AppVeyor¹ / Azure Pipelines / GitHub Actions | Travis CI | Cirrus CI | | CircleCI¹ / GitHub Actions / GitLab¹ |
|
||||
| macOS | AppVeyor¹ / Azure Pipelines | | Cirrus CI | GitLab¹ | CircleCI¹ / GitHub Actions |
|
||||
| Windows | AppVeyor¹ / Azure Pipelines | Travis CI | Cirrus CI | | GitHub Actions / GitLab¹ |
|
||||
| | 3.8 | 3.9 | 3.10 | 3.11 | 3.12 |
|
||||
|---------|----------------------------------|-----------|-----------|---------|--------------------------------------------------|
|
||||
| Linux | Azure Pipelines / GitHub Actions | Travis CI | Cirrus CI | | AppVeyor¹ / CircleCI¹ / GitHub Actions / GitLab¹ |
|
||||
| macOS | Azure Pipelines | | Cirrus CI | GitLab¹ | AppVeyor¹ /CircleCI¹ / GitHub Actions |
|
||||
| Windows | Azure Pipelines | Travis CI | Cirrus CI | | AppVeyor¹ / GitHub Actions / GitLab¹ |
|
||||
|
||||
> ¹ Runs a reduced set of tests to reduce CI load
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
- uses: actions/setup-python@v5
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: python -m pip install cibuildwheel==2.20.0
|
||||
run: python -m pip install cibuildwheel==2.21.0
|
||||
|
||||
- name: Build wheels
|
||||
run: python -m cibuildwheel --output-dir wheelhouse
|
||||
@@ -161,8 +161,8 @@ Here are some repos that use cibuildwheel.
|
||||
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
||||
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
||||
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
|
||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
||||
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
||||
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
||||
@@ -172,8 +172,8 @@ Here are some repos that use cibuildwheel.
|
||||
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
||||
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
|
||||
[NumPy]: https://github.com/numpy/numpy
|
||||
[Tornado]: https://github.com/tornadoweb/tornado
|
||||
[duckdb]: https://github.com/duckdb/duckdb
|
||||
[Tornado]: https://github.com/tornadoweb/tornado
|
||||
[NCNN]: https://github.com/Tencent/ncnn
|
||||
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
||||
[Prophet]: https://github.com/facebook/prophet
|
||||
@@ -211,8 +211,22 @@ Changelog
|
||||
|
||||
<!-- this section was generated by bin/update_readme_changelog.py -- do not edit manually -->
|
||||
|
||||
### v2.21.0
|
||||
|
||||
_13 September 2024_
|
||||
|
||||
- ⚠️ Update CPython 3.12 to 3.12.6, which changes the macOS minimum deployment target on CPython 3.12 from macOS 10.9 to macOS 10.13 (#1998)
|
||||
- 🛠 Changes the behaviour when inheriting `config-settings` in TOML overrides - rather than extending each key, which is rarely useful, individual keys will override previously set values. (#1803)
|
||||
- 🛠 Update CPython 3.13 to 3.13.0rc2 (#1998)
|
||||
- ✨ Adds support for multiarch OCI images (#1961)
|
||||
- 🐛 Fixes some bugs building Linux wheels on macOS. (#1961)
|
||||
- ⚠️ Changes the minimum version of Docker/Podman to Docker API version 1.43, Podman API version 3. The only mainstream runner this should affect is Travis Graviton2 runners - if so you can [upgrade your version of Docker](https://github.com/pypa/cibuildwheel/pull/1961#issuecomment-2304060019). (#1961)
|
||||
|
||||
|
||||
### v2.20.0
|
||||
|
||||
_4 August 2024_
|
||||
|
||||
- 🌟 CPython 3.13 wheels are now built by default - without the `CIBW_PRERELEASE_PYTHONS` flag. It's time to build and upload these wheels to PyPI! This release includes CPython 3.13.0rc1, which is guaranteed to be ABI compatible with the final release. Free-threading is still behind a flag/config option. (#1950)
|
||||
- ✨ Provide a `CIBW_ALLOW_EMPTY` environment variable as an alternative to the command line flag. (#1937)
|
||||
- 🐛 Don't use uv on PyPy3.8 on Windows, it stopped working starting in 0.2.25. Note that PyPy 3.8 is EoL. (#1868)
|
||||
@@ -223,6 +237,8 @@ Changelog
|
||||
|
||||
### v2.19.2
|
||||
|
||||
_2 July 2024_
|
||||
|
||||
- 🐛 Update manylinux2014 pins to versions that support past-EoL CentOS 7 mirrors. (#1917)
|
||||
- 🐛 Support `--no-isolation` with `build[uv]` build-frontend. (#1889)
|
||||
- 🛠 Provide attestations for releases at <https://github.com/pypa/cibuildwheel/attestations>. (#1916)
|
||||
@@ -235,6 +251,8 @@ Changelog
|
||||
|
||||
### v2.19.1
|
||||
|
||||
_13 June 2024_
|
||||
|
||||
- 🐛 Don't require setup-python on GHA for Pyodide (#1868)
|
||||
- 🐛 Specify full python path for uv (fixes issue in 0.2.10 & 0.2.11) (#1881)
|
||||
- 🛠 Update for pip 24.1b2 on CPython 3.13. (#1879)
|
||||
@@ -244,6 +262,8 @@ Changelog
|
||||
|
||||
### v2.19.0
|
||||
|
||||
_10 June 2024_
|
||||
|
||||
See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more info on new features!
|
||||
|
||||
- 🌟 Add Pyodide platform. Set with `--platform pyodide` or `CIBW_PLATFORM: pyodide` on Linux with a host Python 3.12 to build WebAssembly wheels. Not accepted on PyPI currently, but usable directly in a website using Pyodide, for live docs, etc. (#1456, #1859)
|
||||
@@ -258,19 +278,6 @@ See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more
|
||||
- 🛠 Single Python tests made more generic. (#1835)
|
||||
- 🛠 Sped up our ci by splitting up emulation tests. (#1839)
|
||||
|
||||
|
||||
|
||||
### v2.18.1
|
||||
|
||||
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
|
||||
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
|
||||
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
|
||||
- 🛠 Significant improvements and modernization to our noxfile. (#1823)
|
||||
- 🛠 Use pylint's new GitHub Actions reporter instead of a custom matcher. (#1823)
|
||||
- 🛠 Unpin virtualenv updates for Python 3.7+ (#1830)
|
||||
- 🐛 Fix running linux tests from Windows or macOS ARM. (#1788)
|
||||
- 📚 Fix our documentation build. (#1821)
|
||||
|
||||
<!-- END bin/update_readme_changelog.py -->
|
||||
|
||||
---
|
||||
|
||||
+14
-11
@@ -1,26 +1,29 @@
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
|
||||
APPVEYOR_JOB_NAME: "python38-x64-ubuntu"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
APPVEYOR_JOB_NAME: "python38-x64-vs2015"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos
|
||||
APPVEYOR_JOB_NAME: "python38-x64-macos"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
|
||||
APPVEYOR_JOB_NAME: "python312-x64-ubuntu"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
APPVEYOR_JOB_NAME: "python312-x64-vs2022"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
|
||||
APPVEYOR_JOB_NAME: "python312-x64-macos"
|
||||
|
||||
stack: python 3.8
|
||||
stack: python 3.12
|
||||
|
||||
build: off
|
||||
|
||||
init:
|
||||
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
|
||||
- ps: |
|
||||
$BRANCH = if ($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH) { $env:APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH } else { $env:APPVEYOR_REPO_BRANCH }
|
||||
if (-not ($BRANCH -eq 'main' -or $BRANCH.ToLower().StartsWith('appveyor-'))) {
|
||||
$env:PYTEST_ADDOPTS='-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
|
||||
$env:PYTEST_ADDOPTS = '-k "unit_test or test_0_basic" --suppress-no-test-exit-code'
|
||||
}
|
||||
if ($IsLinux) {
|
||||
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
}
|
||||
python -m pip install -U pip
|
||||
|
||||
install: python -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||
install:
|
||||
- python -m pip install -U pip
|
||||
- python -m pip install -e ".[dev]" pytest-custom-exit-code
|
||||
|
||||
# the '-u' flag is required so the output is in the correct order.
|
||||
# See https://github.com/pypa/cibuildwheel/pull/24 for more info.
|
||||
|
||||
@@ -13,6 +13,7 @@ jobs:
|
||||
inputs:
|
||||
versionSpec: '3.8'
|
||||
- bash: |
|
||||
docker run --rm --privileged docker.io/tonistiigi/binfmt:latest --install all
|
||||
python -m pip install -e ".[dev]"
|
||||
python ./bin/run_tests.py
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ if __name__ == "__main__":
|
||||
# unit tests
|
||||
unit_test_args = [sys.executable, "-m", "pytest", "unit_test"]
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
if sys.platform.startswith("linux") and os.environ.get("CIBW_PLATFORM", "linux") == "linux":
|
||||
# run the docker unit tests only on Linux
|
||||
unit_test_args += ["--run-docker"]
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
from __future__ import annotations
|
||||
|
||||
__version__ = "2.20.0"
|
||||
__version__ = "2.21.0"
|
||||
|
||||
@@ -240,7 +240,7 @@ def _compute_platform_auto() -> PlatformName:
|
||||
|
||||
|
||||
def _compute_platform(args: CommandLineArguments) -> PlatformName:
|
||||
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "auto")
|
||||
platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "") or "auto"
|
||||
|
||||
if args.only and args.platform is not None:
|
||||
msg = "--platform cannot be specified with --only, it is computed from --only"
|
||||
|
||||
@@ -64,7 +64,9 @@ class Architecture(Enum):
|
||||
if arch_str == "auto":
|
||||
result |= Architecture.auto_archs(platform=platform)
|
||||
elif arch_str == "native":
|
||||
result.add(Architecture(platform_module.machine()))
|
||||
native_arch = Architecture.native_arch(platform=platform)
|
||||
if native_arch:
|
||||
result.add(native_arch)
|
||||
elif arch_str == "all":
|
||||
result |= Architecture.all_archs(platform=platform)
|
||||
elif arch_str == "auto64":
|
||||
|
||||
@@ -58,3 +58,7 @@ class AlreadyBuiltWheelError(FatalError):
|
||||
)
|
||||
super().__init__(message)
|
||||
self.return_code = 6
|
||||
|
||||
|
||||
class OCIEngineTooOldError(FatalError):
|
||||
return_code = 7
|
||||
|
||||
+13
-4
@@ -14,7 +14,7 @@ from . import errors
|
||||
from ._compat.typing import assert_never
|
||||
from .architecture import Architecture
|
||||
from .logger import log
|
||||
from .oci_container import OCIContainer, OCIContainerEngineConfig
|
||||
from .oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
|
||||
from .options import BuildOptions, Options
|
||||
from .typing import PathOrStr
|
||||
from .util import (
|
||||
@@ -29,6 +29,14 @@ from .util import (
|
||||
unwrap,
|
||||
)
|
||||
|
||||
ARCHITECTURE_OCI_PLATFORM_MAP = {
|
||||
Architecture.x86_64: OCIPlatform.AMD64,
|
||||
Architecture.i686: OCIPlatform.i386,
|
||||
Architecture.aarch64: OCIPlatform.ARM64,
|
||||
Architecture.ppc64le: OCIPlatform.PPC64LE,
|
||||
Architecture.s390x: OCIPlatform.S390X,
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PythonConfiguration:
|
||||
@@ -196,6 +204,8 @@ def build_in_container(
|
||||
|
||||
dependency_constraint_flags: list[PathOrStr] = []
|
||||
|
||||
log.step("Setting up build environment...")
|
||||
|
||||
if build_options.dependency_constraints:
|
||||
constraints_file = build_options.dependency_constraints.get_for_python_version(
|
||||
config.version
|
||||
@@ -205,8 +215,6 @@ def build_in_container(
|
||||
container.copy_into(constraints_file, container_constraints_file)
|
||||
dependency_constraint_flags = ["-c", container_constraints_file]
|
||||
|
||||
log.step("Setting up build environment...")
|
||||
|
||||
env = container.get_environment()
|
||||
env["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||
env["PIP_ROOT_USER_ACTION"] = "ignore"
|
||||
@@ -446,10 +454,11 @@ def build(options: Options, tmp_path: Path) -> None: # noqa: ARG001
|
||||
log.step(f"Starting container image {build_step.container_image}...")
|
||||
|
||||
print(f"info: This container will host the build for {', '.join(ids_to_build)}...")
|
||||
architecture = Architecture(build_step.platform_tag.split("_", 1)[1])
|
||||
|
||||
with OCIContainer(
|
||||
image=build_step.container_image,
|
||||
enforce_32_bit=build_step.platform_tag.endswith("i686"),
|
||||
oci_platform=ARCHITECTURE_OCI_PLATFORM_MAP[architecture],
|
||||
cwd=container_project_path,
|
||||
engine=build_step.container_engine,
|
||||
) as container:
|
||||
|
||||
@@ -294,10 +294,10 @@ def setup_python(
|
||||
# Set MACOSX_DEPLOYMENT_TARGET, if the user didn't set it.
|
||||
# For arm64, the minimal deployment target is 11.0.
|
||||
# On x86_64 (or universal2), use 10.9 as a default.
|
||||
# CPython 3.13 needs 10.13.
|
||||
# CPython 3.12.6+ needs 10.13.
|
||||
if config_is_arm64:
|
||||
default_target = "11.0"
|
||||
elif Version(python_configuration.version) >= Version("3.13"):
|
||||
elif Version(python_configuration.version) >= Version("3.12"):
|
||||
default_target = "10.13"
|
||||
elif python_configuration.identifier.startswith("pp") and Version(
|
||||
python_configuration.version
|
||||
|
||||
+100
-68
@@ -5,18 +5,22 @@ import json
|
||||
import os
|
||||
import platform
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import typing
|
||||
import uuid
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from pathlib import Path, PurePath, PurePosixPath
|
||||
from types import TracebackType
|
||||
from typing import IO, Dict, Literal
|
||||
|
||||
from ._compat.typing import Self
|
||||
from packaging.version import InvalidVersion, Version
|
||||
|
||||
from ._compat.typing import Self, assert_never
|
||||
from .errors import OCIEngineTooOldError
|
||||
from .logger import log
|
||||
from .typing import PathOrStr, PopenBytes
|
||||
from .util import (
|
||||
CIProvider,
|
||||
@@ -29,6 +33,15 @@ from .util import (
|
||||
ContainerEngineName = Literal["docker", "podman"]
|
||||
|
||||
|
||||
# Order of the enum matters for tests. 386 shall appear before amd64.
|
||||
class OCIPlatform(Enum):
|
||||
i386 = "linux/386"
|
||||
AMD64 = "linux/amd64"
|
||||
ARM64 = "linux/arm64"
|
||||
PPC64LE = "linux/ppc64le"
|
||||
S390X = "linux/s390x"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OCIContainerEngineConfig:
|
||||
name: ContainerEngineName
|
||||
@@ -56,6 +69,15 @@ class OCIContainerEngineConfig:
|
||||
disable_host_mount = (
|
||||
strtobool(disable_host_mount_options[-1]) if disable_host_mount_options else False
|
||||
)
|
||||
if "--platform" in create_args or any(arg.startswith("--platform=") for arg in create_args):
|
||||
msg = "Using '--platform' in 'container-engine::create_args' is deprecated. It will be ignored."
|
||||
log.warning(msg)
|
||||
if "--platform" in create_args:
|
||||
index = create_args.index("--platform")
|
||||
create_args.pop(index)
|
||||
create_args.pop(index)
|
||||
else:
|
||||
create_args = [arg for arg in create_args if not arg.startswith("--platform=")]
|
||||
|
||||
return OCIContainerEngineConfig(
|
||||
name=name, create_args=tuple(create_args), disable_host_mount=disable_host_mount
|
||||
@@ -75,6 +97,32 @@ class OCIContainerEngineConfig:
|
||||
DEFAULT_ENGINE = OCIContainerEngineConfig("docker")
|
||||
|
||||
|
||||
def _check_engine_version(engine: OCIContainerEngineConfig) -> None:
|
||||
try:
|
||||
version_string = call(engine.name, "version", "-f", "{{json .}}", capture_stdout=True)
|
||||
version_info = json.loads(version_string.strip())
|
||||
if engine.name == "docker":
|
||||
# --platform support was introduced in 1.32 as experimental
|
||||
# docker cp, as used by cibuildwheel, has been fixed in v24 => API 1.43, https://github.com/moby/moby/issues/38995
|
||||
client_api_version = Version(version_info["Client"]["ApiVersion"])
|
||||
engine_api_version = Version(version_info["Server"]["ApiVersion"])
|
||||
version_supported = min(client_api_version, engine_api_version) >= Version("1.43")
|
||||
elif engine.name == "podman":
|
||||
client_api_version = Version(version_info["Client"]["APIVersion"])
|
||||
if "Server" in version_info:
|
||||
engine_api_version = Version(version_info["Server"]["APIVersion"])
|
||||
else:
|
||||
engine_api_version = client_api_version
|
||||
# --platform support was introduced in v3
|
||||
version_supported = min(client_api_version, engine_api_version) >= Version("3")
|
||||
else:
|
||||
assert_never(engine.name)
|
||||
if not version_supported:
|
||||
raise OCIEngineTooOldError() from None
|
||||
except (subprocess.CalledProcessError, KeyError, InvalidVersion) as e:
|
||||
raise OCIEngineTooOldError() from e
|
||||
|
||||
|
||||
class OCIContainer:
|
||||
"""
|
||||
An object that represents a running OCI (e.g. Docker) container.
|
||||
@@ -108,7 +156,7 @@ class OCIContainer:
|
||||
self,
|
||||
*,
|
||||
image: str,
|
||||
enforce_32_bit: bool = False,
|
||||
oci_platform: OCIPlatform,
|
||||
cwd: PathOrStr | None = None,
|
||||
engine: OCIContainerEngineConfig = DEFAULT_ENGINE,
|
||||
):
|
||||
@@ -117,14 +165,41 @@ class OCIContainer:
|
||||
raise ValueError(msg)
|
||||
|
||||
self.image = image
|
||||
self.enforce_32_bit = enforce_32_bit
|
||||
self.oci_platform = oci_platform
|
||||
self.cwd = cwd
|
||||
self.name: str | None = None
|
||||
self.engine = engine
|
||||
|
||||
def _get_platform_args(self, *, oci_platform: OCIPlatform | None = None) -> tuple[str, str]:
|
||||
if oci_platform is None:
|
||||
oci_platform = self.oci_platform
|
||||
|
||||
# we need '--pull=always' otherwise some images with the wrong platform get re-used (e.g. 386 image for amd64)
|
||||
# c.f. https://github.com/moby/moby/issues/48197#issuecomment-2282802313
|
||||
pull = "always"
|
||||
try:
|
||||
image_platform = call(
|
||||
self.engine.name,
|
||||
"image",
|
||||
"inspect",
|
||||
self.image,
|
||||
"--format",
|
||||
"{{.Os}}/{{.Architecture}}",
|
||||
capture_stdout=True,
|
||||
).strip()
|
||||
if image_platform == oci_platform.value:
|
||||
# in case the correct image is already present, don't pull
|
||||
# this allows to run local only images
|
||||
pull = "never"
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
return f"--platform={oci_platform.value}", f"--pull={pull}"
|
||||
|
||||
def __enter__(self) -> Self:
|
||||
self.name = f"cibuildwheel-{uuid.uuid4()}"
|
||||
|
||||
_check_engine_version(self.engine)
|
||||
|
||||
# work-around for Travis-CI PPC64le Docker runs since 2021:
|
||||
# this avoids network splits
|
||||
# https://github.com/pypa/cibuildwheel/issues/904
|
||||
@@ -133,14 +208,26 @@ class OCIContainer:
|
||||
if detect_ci_provider() == CIProvider.travis_ci and platform.machine() == "ppc64le":
|
||||
network_args = ["--network=host"]
|
||||
|
||||
platform_args = self._get_platform_args()
|
||||
|
||||
simulate_32_bit = False
|
||||
if self.enforce_32_bit:
|
||||
if self.oci_platform == OCIPlatform.i386:
|
||||
# If the architecture running the image is already the right one
|
||||
# or the image entrypoint takes care of enforcing this, then we don't need to
|
||||
# simulate this
|
||||
container_machine = call(
|
||||
self.engine.name, "run", "--rm", self.image, "uname", "-m", capture_stdout=True
|
||||
).strip()
|
||||
run_cmd = [self.engine.name, "run", "--rm"]
|
||||
ctr_cmd = ["uname", "-m"]
|
||||
try:
|
||||
container_machine = call(
|
||||
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
|
||||
).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
# The image might have been built with amd64 architecture
|
||||
# Let's try that
|
||||
platform_args = self._get_platform_args(oci_platform=OCIPlatform.AMD64)
|
||||
container_machine = call(
|
||||
*run_cmd, *platform_args, self.image, *ctr_cmd, capture_stdout=True
|
||||
).strip()
|
||||
simulate_32_bit = container_machine != "i686"
|
||||
|
||||
shell_args = ["linux32", "/bin/bash"] if simulate_32_bit else ["/bin/bash"]
|
||||
@@ -155,6 +242,7 @@ class OCIContainer:
|
||||
"--interactive",
|
||||
*(["--volume=/:/host"] if not self.engine.disable_host_mount else []),
|
||||
*network_args,
|
||||
*platform_args,
|
||||
*self.engine.create_args,
|
||||
self.image,
|
||||
*shell_args,
|
||||
@@ -221,73 +309,17 @@ class OCIContainer:
|
||||
self.name = None
|
||||
|
||||
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
|
||||
# `docker cp` causes 'no space left on device' error when
|
||||
# a container is running and the host filesystem is
|
||||
# mounted. https://github.com/moby/moby/issues/38995
|
||||
# Use `docker exec` instead.
|
||||
|
||||
if from_path.is_dir():
|
||||
self.call(["mkdir", "-p", to_path])
|
||||
subprocess.run(
|
||||
f"tar cf - . | {self.engine.name} exec -i {self.name} tar --no-same-owner -xC {shell_quote(to_path)} -f -",
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=from_path,
|
||||
)
|
||||
call(self.engine.name, "cp", f"{from_path}/.", f"{self.name}:{to_path}")
|
||||
else:
|
||||
exec_process: subprocess.Popen[bytes]
|
||||
with subprocess.Popen(
|
||||
[
|
||||
self.engine.name,
|
||||
"exec",
|
||||
"-i",
|
||||
str(self.name),
|
||||
"sh",
|
||||
"-c",
|
||||
f"cat > {shell_quote(to_path)}",
|
||||
],
|
||||
stdin=subprocess.PIPE,
|
||||
) as exec_process:
|
||||
assert exec_process.stdin
|
||||
with open(from_path, "rb") as from_file:
|
||||
# Bug in mypy, https://github.com/python/mypy/issues/15031
|
||||
shutil.copyfileobj(from_file, exec_process.stdin) # type: ignore[misc]
|
||||
|
||||
exec_process.stdin.close()
|
||||
exec_process.wait()
|
||||
|
||||
if exec_process.returncode:
|
||||
raise subprocess.CalledProcessError(
|
||||
exec_process.returncode, exec_process.args, None, None
|
||||
)
|
||||
self.call(["mkdir", "-p", to_path.parent])
|
||||
call(self.engine.name, "cp", from_path, f"{self.name}:{to_path}")
|
||||
|
||||
def copy_out(self, from_path: PurePath, to_path: Path) -> None:
|
||||
# note: we assume from_path is a dir
|
||||
to_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if self.engine.name == "podman":
|
||||
subprocess.run(
|
||||
[
|
||||
self.engine.name,
|
||||
"cp",
|
||||
f"{self.name}:{from_path}/.",
|
||||
str(to_path),
|
||||
],
|
||||
check=True,
|
||||
cwd=to_path,
|
||||
)
|
||||
elif self.engine.name == "docker":
|
||||
# There is a bug in docker that prevents a simple 'cp' invocation
|
||||
# from working https://github.com/moby/moby/issues/38995
|
||||
command = f"{self.engine.name} exec -i {self.name} tar -cC {shell_quote(from_path)} -f - . | tar -xf -"
|
||||
subprocess.run(
|
||||
command,
|
||||
shell=True,
|
||||
check=True,
|
||||
cwd=to_path,
|
||||
)
|
||||
else:
|
||||
raise KeyError(self.engine.name)
|
||||
call(self.engine.name, "cp", f"{self.name}:{from_path}/.", to_path)
|
||||
|
||||
def glob(self, path: PurePosixPath, pattern: str) -> list[PurePosixPath]:
|
||||
glob_pattern = path.joinpath(pattern)
|
||||
|
||||
+179
-93
@@ -9,15 +9,15 @@ import enum
|
||||
import functools
|
||||
import shlex
|
||||
import textwrap
|
||||
from collections.abc import Callable, Generator, Iterable, Iterator, Set
|
||||
from collections.abc import Generator, Iterable, Set
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal, Mapping, Sequence, TypedDict, Union # noqa: TID251
|
||||
from typing import Any, Literal, Mapping, Sequence, Union # noqa: TID251
|
||||
|
||||
from packaging.specifiers import SpecifierSet
|
||||
|
||||
from . import errors
|
||||
from ._compat import tomllib
|
||||
from ._compat.typing import NotRequired, assert_never
|
||||
from ._compat.typing import assert_never
|
||||
from .architecture import Architecture
|
||||
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
|
||||
from .logger import log
|
||||
@@ -118,13 +118,16 @@ class BuildOptions:
|
||||
return self.globals.architectures
|
||||
|
||||
|
||||
Setting = Union[Mapping[str, str], Sequence[str], str, int, bool]
|
||||
SettingLeaf = Union[str, int, bool]
|
||||
SettingList = Sequence[SettingLeaf]
|
||||
SettingTable = Mapping[str, Union[SettingLeaf, SettingList]]
|
||||
SettingValue = Union[SettingTable, SettingList, SettingLeaf]
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class Override:
|
||||
select_pattern: str
|
||||
options: dict[str, Setting]
|
||||
options: dict[str, SettingValue]
|
||||
inherit: dict[str, InheritRule]
|
||||
|
||||
|
||||
@@ -137,22 +140,123 @@ DISALLOWED_OPTIONS = {
|
||||
}
|
||||
|
||||
|
||||
class TableFmt(TypedDict):
|
||||
# a format string, used with '.format', with `k` and `v` parameters
|
||||
# e.g. "{k}={v}"
|
||||
item: str
|
||||
# the string that is inserted between items
|
||||
# e.g. " "
|
||||
sep: str
|
||||
# a quoting function that, if supplied, is called to quote each value
|
||||
# e.g. shlex.quote
|
||||
quote: NotRequired[Callable[[str], str]]
|
||||
|
||||
|
||||
class ConfigOptionError(KeyError):
|
||||
class OptionsReaderError(errors.ConfigurationError):
|
||||
pass
|
||||
|
||||
|
||||
class OptionFormat:
|
||||
"""
|
||||
Base class for option format specifiers. These objects describe how values
|
||||
can be parsed from rich TOML values and how they're merged together.
|
||||
"""
|
||||
|
||||
class NotSupported(Exception):
|
||||
pass
|
||||
|
||||
def format_list(self, value: SettingList) -> str: # noqa: ARG002
|
||||
raise OptionFormat.NotSupported
|
||||
|
||||
def format_table(self, table: SettingTable) -> str: # noqa: ARG002
|
||||
raise OptionFormat.NotSupported
|
||||
|
||||
def merge_values(self, before: str, after: str) -> str: # noqa: ARG002
|
||||
raise OptionFormat.NotSupported
|
||||
|
||||
|
||||
class ListFormat(OptionFormat):
|
||||
"""
|
||||
A format that joins lists with a separator.
|
||||
"""
|
||||
|
||||
def __init__(self, sep: str) -> None:
|
||||
self.sep = sep
|
||||
|
||||
def format_list(self, value: SettingList) -> str:
|
||||
return self.sep.join(str(v) for v in value)
|
||||
|
||||
def merge_values(self, before: str, after: str) -> str:
|
||||
return f"{before}{self.sep}{after}"
|
||||
|
||||
|
||||
class ShlexTableFormat(OptionFormat):
|
||||
"""
|
||||
The standard table format uses shlex.quote to quote values and shlex.split
|
||||
to unquote and split them. When merging values, keys in before are
|
||||
replaced by keys in after.
|
||||
"""
|
||||
|
||||
def __init__(self, sep: str = " ", pair_sep: str = "=", allow_merge: bool = True) -> None:
|
||||
self.sep = sep
|
||||
self.pair_sep = pair_sep
|
||||
self.allow_merge = allow_merge
|
||||
|
||||
def format_table(self, table: SettingTable) -> str:
|
||||
assignments: list[tuple[str, str]] = []
|
||||
|
||||
for k, v in table.items():
|
||||
if shlex.split(k) != [k]:
|
||||
msg = f"Invalid table key: {k}"
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
if isinstance(v, str):
|
||||
assignments.append((k, v))
|
||||
elif isinstance(v, Sequence):
|
||||
for inner_v in v:
|
||||
assignments.append((k, str(inner_v)))
|
||||
else:
|
||||
assignments.append((k, str(v)))
|
||||
|
||||
return self.sep.join(f"{k}{self.pair_sep}{shlex.quote(v)}" for k, v in assignments)
|
||||
|
||||
def merge_values(self, before: str, after: str) -> str:
|
||||
if not self.allow_merge:
|
||||
raise OptionFormat.NotSupported
|
||||
|
||||
before_dict = self.parse_table(before)
|
||||
after_dict = self.parse_table(after)
|
||||
|
||||
return self.format_table({**before_dict, **after_dict})
|
||||
|
||||
def parse_table(self, table: str) -> Mapping[str, str | Sequence[str]]:
|
||||
assignments: list[tuple[str, str]] = []
|
||||
|
||||
for assignment_str in shlex.split(table):
|
||||
key, sep, value = assignment_str.partition(self.pair_sep)
|
||||
|
||||
if not sep:
|
||||
msg = f"malformed option with value {assignment_str!r}"
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
assignments.append((key, value))
|
||||
|
||||
result: dict[str, str | list[str]] = {}
|
||||
|
||||
for key, value in assignments:
|
||||
if key in result:
|
||||
existing_value = result[key]
|
||||
if isinstance(existing_value, list):
|
||||
result[key] = [*existing_value, value]
|
||||
else:
|
||||
result[key] = [existing_value, value]
|
||||
else:
|
||||
result[key] = value
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class EnvironmentFormat(OptionFormat):
|
||||
"""
|
||||
The environment format accepts a table of environment variables, where the
|
||||
values may contain variables or command substitutions.
|
||||
"""
|
||||
|
||||
def format_table(self, table: SettingTable) -> str:
|
||||
return " ".join(f'{k}="{v}"' for k, v in table.items())
|
||||
|
||||
def merge_values(self, before: str, after: str) -> str:
|
||||
return f"{before} {after}"
|
||||
|
||||
|
||||
class InheritRule(enum.Enum):
|
||||
NONE = enum.auto()
|
||||
APPEND = enum.auto()
|
||||
@@ -160,10 +264,9 @@ class InheritRule(enum.Enum):
|
||||
|
||||
|
||||
def _resolve_cascade(
|
||||
*pairs: tuple[Setting | None, InheritRule],
|
||||
*pairs: tuple[SettingValue | None, InheritRule],
|
||||
ignore_empty: bool = False,
|
||||
list_sep: str | None = None,
|
||||
table_format: TableFmt | None = None,
|
||||
option_format: OptionFormat | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Given a cascade of values with inherit rules, resolve them into a single
|
||||
@@ -186,13 +289,6 @@ def _resolve_cascade(
|
||||
|
||||
result: str | None = None
|
||||
|
||||
if table_format is not None:
|
||||
merge_sep = table_format["sep"]
|
||||
elif list_sep is not None:
|
||||
merge_sep = list_sep
|
||||
else:
|
||||
merge_sep = None
|
||||
|
||||
for value, rule in pairs:
|
||||
if value is None:
|
||||
continue
|
||||
@@ -200,14 +296,9 @@ def _resolve_cascade(
|
||||
if ignore_empty and not value and value is not False:
|
||||
continue
|
||||
|
||||
value_string = _stringify_setting(value, list_sep, table_format)
|
||||
value_string = _stringify_setting(value, option_format=option_format)
|
||||
|
||||
result = _merge_values(
|
||||
result,
|
||||
value_string,
|
||||
rule=rule,
|
||||
merge_sep=merge_sep,
|
||||
)
|
||||
result = _apply_inherit_rule(result, value_string, rule=rule, option_format=option_format)
|
||||
|
||||
if result is None:
|
||||
msg = "a setting should at least have a default value"
|
||||
@@ -217,7 +308,9 @@ def _resolve_cascade(
|
||||
|
||||
|
||||
# pylint: disable-next=inconsistent-return-statements
|
||||
def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep: str | None) -> str:
|
||||
def _apply_inherit_rule(
|
||||
before: str | None, after: str, rule: InheritRule, option_format: OptionFormat | None
|
||||
) -> str:
|
||||
if rule == InheritRule.NONE:
|
||||
return after
|
||||
|
||||
@@ -230,34 +323,39 @@ def _merge_values(before: str | None, after: str, rule: InheritRule, merge_sep:
|
||||
# if after is an empty string, we shouldn't add any separator
|
||||
return before
|
||||
|
||||
if not merge_sep:
|
||||
if not option_format:
|
||||
msg = f"Don't know how to merge {before!r} and {after!r} with {rule}"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
if rule == InheritRule.APPEND:
|
||||
return f"{before}{merge_sep}{after}"
|
||||
return option_format.merge_values(before, after)
|
||||
elif rule == InheritRule.PREPEND:
|
||||
return f"{after}{merge_sep}{before}"
|
||||
return option_format.merge_values(after, before)
|
||||
else:
|
||||
assert_never(rule)
|
||||
|
||||
|
||||
def _stringify_setting(
|
||||
setting: Setting, list_sep: str | None, table_format: TableFmt | None
|
||||
setting: SettingValue,
|
||||
option_format: OptionFormat | None,
|
||||
) -> str:
|
||||
if isinstance(setting, Mapping):
|
||||
if table_format is None:
|
||||
try:
|
||||
if option_format is None:
|
||||
raise OptionFormat.NotSupported
|
||||
return option_format.format_table(setting)
|
||||
except OptionFormat.NotSupported:
|
||||
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a table"
|
||||
raise ConfigOptionError(msg)
|
||||
return table_format["sep"].join(
|
||||
item for k, v in setting.items() for item in _inner_fmt(k, v, table_format)
|
||||
)
|
||||
raise OptionsReaderError(msg) from None
|
||||
|
||||
if not isinstance(setting, str) and isinstance(setting, Sequence):
|
||||
if list_sep is None:
|
||||
try:
|
||||
if option_format is None:
|
||||
raise OptionFormat.NotSupported
|
||||
return option_format.format_list(setting)
|
||||
except OptionFormat.NotSupported:
|
||||
msg = f"Error converting {setting!r} to a string: this setting doesn't accept a list"
|
||||
raise ConfigOptionError(msg)
|
||||
return list_sep.join(setting)
|
||||
raise OptionsReaderError(msg) from None
|
||||
|
||||
if isinstance(setting, (bool, int)):
|
||||
return str(setting)
|
||||
@@ -323,14 +421,14 @@ class OptionsReader:
|
||||
if config_overrides is not None:
|
||||
if not isinstance(config_overrides, list):
|
||||
msg = "'tool.cibuildwheel.overrides' must be a list"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
for config_override in config_overrides:
|
||||
select = config_override.pop("select", None)
|
||||
|
||||
if not select:
|
||||
msg = "'select' must be set in an override"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
if isinstance(select, list):
|
||||
select = " ".join(select)
|
||||
@@ -340,7 +438,7 @@ class OptionsReader:
|
||||
i in {"none", "append", "prepend"} for i in inherit.values()
|
||||
):
|
||||
msg = "'inherit' must be a dict containing only {'none', 'append', 'prepend'} values"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
inherit_enum = {k: InheritRule[v.upper()] for k, v in inherit.items()}
|
||||
|
||||
@@ -358,7 +456,7 @@ class OptionsReader:
|
||||
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
||||
if matches:
|
||||
msg += f" Perhaps you meant {matches[0]!r}?"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
def _validate_platform_option(self, name: str) -> None:
|
||||
"""
|
||||
@@ -368,7 +466,7 @@ class OptionsReader:
|
||||
disallowed_platform_options = self.disallow.get(self.platform, set())
|
||||
if name in disallowed_platform_options:
|
||||
msg = f"{name!r} is not allowed in {disallowed_platform_options}"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
allowed_option_names = self.default_options.keys() | self.default_platform_options.keys()
|
||||
|
||||
@@ -377,7 +475,7 @@ class OptionsReader:
|
||||
matches = difflib.get_close_matches(name, allowed_option_names, 1, 0.7)
|
||||
if matches:
|
||||
msg += f" Perhaps you meant {matches[0]!r}?"
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
def _load_file(self, filename: Path) -> tuple[dict[str, Any], dict[str, Any]]:
|
||||
"""
|
||||
@@ -412,8 +510,7 @@ class OptionsReader:
|
||||
name: str,
|
||||
*,
|
||||
env_plat: bool = True,
|
||||
list_sep: str | None = None,
|
||||
table_format: TableFmt | None = None,
|
||||
option_format: OptionFormat | None = None,
|
||||
ignore_empty: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
@@ -429,7 +526,7 @@ class OptionsReader:
|
||||
|
||||
if name not in self.default_options and name not in self.default_platform_options:
|
||||
msg = f"{name!r} must be in cibuildwheel/resources/defaults.toml file to be accessed."
|
||||
raise ConfigOptionError(msg)
|
||||
raise OptionsReaderError(msg)
|
||||
|
||||
# Environment variable form
|
||||
envvar = f"CIBW_{name.upper().replace('-', '_')}"
|
||||
@@ -449,26 +546,10 @@ class OptionsReader:
|
||||
(self.env.get(envvar), InheritRule.NONE),
|
||||
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
|
||||
ignore_empty=ignore_empty,
|
||||
list_sep=list_sep,
|
||||
table_format=table_format,
|
||||
option_format=option_format,
|
||||
)
|
||||
|
||||
|
||||
def _inner_fmt(k: str, v: Any, table: TableFmt) -> Iterator[str]:
|
||||
quote_function = table.get("quote", lambda a: a)
|
||||
|
||||
if isinstance(v, list):
|
||||
for inner_v in v:
|
||||
qv = quote_function(inner_v)
|
||||
yield table["item"].format(k=k, v=qv)
|
||||
elif isinstance(v, bool):
|
||||
qv = quote_function(str(v))
|
||||
yield table["item"].format(k=k, v=qv)
|
||||
else:
|
||||
qv = quote_function(v)
|
||||
yield table["item"].format(k=k, v=qv)
|
||||
|
||||
|
||||
class Options:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -513,9 +594,11 @@ class Options:
|
||||
package_dir = args.package_dir
|
||||
output_dir = args.output_dir
|
||||
|
||||
build_config = self.reader.get("build", env_plat=False, list_sep=" ") or "*"
|
||||
skip_config = self.reader.get("skip", env_plat=False, list_sep=" ")
|
||||
test_skip = self.reader.get("test-skip", env_plat=False, list_sep=" ")
|
||||
build_config = (
|
||||
self.reader.get("build", env_plat=False, option_format=ListFormat(sep=" ")) or "*"
|
||||
)
|
||||
skip_config = self.reader.get("skip", env_plat=False, option_format=ListFormat(sep=" "))
|
||||
test_skip = self.reader.get("test-skip", env_plat=False, option_format=ListFormat(sep=" "))
|
||||
|
||||
free_threaded_support = strtobool(
|
||||
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
|
||||
@@ -534,7 +617,7 @@ class Options:
|
||||
)
|
||||
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
|
||||
|
||||
archs_config_str = args.archs or self.reader.get("archs", list_sep=" ")
|
||||
archs_config_str = args.archs or self.reader.get("archs", option_format=ListFormat(sep=" "))
|
||||
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
|
||||
|
||||
# Process `--only`
|
||||
@@ -569,30 +652,33 @@ class Options:
|
||||
"""
|
||||
|
||||
with self.reader.identifier(identifier):
|
||||
before_all = self.reader.get("before-all", list_sep=" && ")
|
||||
before_all = self.reader.get("before-all", option_format=ListFormat(sep=" && "))
|
||||
|
||||
environment_config = self.reader.get(
|
||||
"environment", table_format={"item": '{k}="{v}"', "sep": " "}
|
||||
environment_config = self.reader.get("environment", option_format=EnvironmentFormat())
|
||||
environment_pass = self.reader.get(
|
||||
"environment-pass", option_format=ListFormat(sep=" ")
|
||||
).split()
|
||||
before_build = self.reader.get("before-build", option_format=ListFormat(sep=" && "))
|
||||
repair_command = self.reader.get(
|
||||
"repair-wheel-command", option_format=ListFormat(sep=" && ")
|
||||
)
|
||||
environment_pass = self.reader.get("environment-pass", list_sep=" ").split()
|
||||
before_build = self.reader.get("before-build", list_sep=" && ")
|
||||
repair_command = self.reader.get("repair-wheel-command", list_sep=" && ")
|
||||
config_settings = self.reader.get(
|
||||
"config-settings",
|
||||
table_format={"item": "{k}={v}", "sep": " ", "quote": shlex.quote},
|
||||
"config-settings", option_format=ShlexTableFormat(sep=" ", pair_sep="=")
|
||||
)
|
||||
|
||||
dependency_versions = self.reader.get("dependency-versions")
|
||||
test_command = self.reader.get("test-command", list_sep=" && ")
|
||||
before_test = self.reader.get("before-test", list_sep=" && ")
|
||||
test_requires = self.reader.get("test-requires", list_sep=" ").split()
|
||||
test_extras = self.reader.get("test-extras", list_sep=",")
|
||||
test_command = self.reader.get("test-command", option_format=ListFormat(sep=" && "))
|
||||
before_test = self.reader.get("before-test", option_format=ListFormat(sep=" && "))
|
||||
test_requires = self.reader.get(
|
||||
"test-requires", option_format=ListFormat(sep=" ")
|
||||
).split()
|
||||
test_extras = self.reader.get("test-extras", option_format=ListFormat(sep=","))
|
||||
build_verbosity_str = self.reader.get("build-verbosity")
|
||||
|
||||
build_frontend_str = self.reader.get(
|
||||
"build-frontend",
|
||||
env_plat=False,
|
||||
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
|
||||
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
|
||||
)
|
||||
build_frontend: BuildFrontendConfig | None
|
||||
if not build_frontend_str or build_frontend_str == "default":
|
||||
@@ -674,7 +760,7 @@ class Options:
|
||||
|
||||
container_engine_str = self.reader.get(
|
||||
"container-engine",
|
||||
table_format={"item": "{k}:{v}", "sep": "; ", "quote": shlex.quote},
|
||||
option_format=ShlexTableFormat(sep="; ", pair_sep=":", allow_merge=False),
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -120,22 +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_arm64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
|
||||
{ identifier = "cp311-macosx_universal2", version = "3.11", url = "https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.4/python-3.12.4-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.4/python-3.12.4-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.4/python-3.12.4-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc1-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_x86_64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_arm64", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
|
||||
{ identifier = "cp312-macosx_universal2", version = "3.12", url = "https://www.python.org/ftp/python/3.12.6/python-3.12.6-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "cp313-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_x86_64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_arm64", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "cp313t-macosx_universal2", version = "3.13", url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0rc2-macos11.pkg" },
|
||||
{ identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-osx64.tar.bz2" },
|
||||
{ identifier = "pp38-macosx_x86_64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_x86_64.tar.bz2" },
|
||||
{ identifier = "pp38-macosx_arm64", version = "3.8", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-macos_arm64.tar.bz2" },
|
||||
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_x86_64.tar.bz2" },
|
||||
{ identifier = "pp39-macosx_arm64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-macos_arm64.tar.bz2" },
|
||||
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.16-macos_x86_64.tar.bz2" },
|
||||
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.16-macos_arm64.tar.bz2" },
|
||||
{ identifier = "pp310-macosx_x86_64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-macos_x86_64.tar.bz2" },
|
||||
{ identifier = "pp310-macosx_arm64", version = "3.10", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-macos_arm64.tar.bz2" },
|
||||
]
|
||||
|
||||
[windows]
|
||||
@@ -152,22 +152,22 @@ python_configurations = [
|
||||
{ identifier = "cp310-win_amd64", version = "3.10.11", arch = "64" },
|
||||
{ identifier = "cp311-win32", version = "3.11.9", arch = "32" },
|
||||
{ identifier = "cp311-win_amd64", version = "3.11.9", arch = "64" },
|
||||
{ identifier = "cp312-win32", version = "3.12.4", arch = "32" },
|
||||
{ identifier = "cp312-win_amd64", version = "3.12.4", arch = "64" },
|
||||
{ identifier = "cp313-win32", version = "3.13.0-rc1", arch = "32" },
|
||||
{ identifier = "cp313t-win32", version = "3.13.0-rc1", arch = "32" },
|
||||
{ identifier = "cp313-win_amd64", version = "3.13.0-rc1", arch = "64" },
|
||||
{ identifier = "cp313t-win_amd64", version = "3.13.0-rc1", arch = "64" },
|
||||
{ identifier = "cp312-win32", version = "3.12.6", arch = "32" },
|
||||
{ identifier = "cp312-win_amd64", version = "3.12.6", arch = "64" },
|
||||
{ identifier = "cp313-win32", version = "3.13.0-rc2", arch = "32" },
|
||||
{ identifier = "cp313t-win32", version = "3.13.0-rc2", arch = "32" },
|
||||
{ identifier = "cp313-win_amd64", version = "3.13.0-rc2", arch = "64" },
|
||||
{ identifier = "cp313t-win_amd64", version = "3.13.0-rc2", arch = "64" },
|
||||
{ identifier = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
|
||||
{ identifier = "cp310-win_arm64", version = "3.10.11", arch = "ARM64" },
|
||||
{ identifier = "cp311-win_arm64", version = "3.11.9", arch = "ARM64" },
|
||||
{ identifier = "cp312-win_arm64", version = "3.12.4", arch = "ARM64" },
|
||||
{ identifier = "cp313-win_arm64", version = "3.13.0-rc1", arch = "ARM64" },
|
||||
{ identifier = "cp313t-win_arm64", version = "3.13.0-rc1", arch = "ARM64" },
|
||||
{ identifier = "cp312-win_arm64", version = "3.12.6", arch = "ARM64" },
|
||||
{ identifier = "cp313-win_arm64", version = "3.13.0-rc2", arch = "ARM64" },
|
||||
{ identifier = "cp313t-win_arm64", version = "3.13.0-rc2", arch = "ARM64" },
|
||||
{ identifier = "pp37-win_amd64", version = "3.7", arch = "64", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.9-win64.zip" },
|
||||
{ identifier = "pp38-win_amd64", version = "3.8", arch = "64", url = "https://downloads.python.org/pypy/pypy3.8-v7.3.11-win64.zip" },
|
||||
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.16-win64.zip" },
|
||||
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.16-win64.zip" },
|
||||
{ identifier = "pp310-win_amd64", version = "3.10", arch = "64", url = "https://downloads.python.org/pypy/pypy3.10-v7.3.17-win64.zip" },
|
||||
]
|
||||
|
||||
[pyodide]
|
||||
|
||||
@@ -6,11 +6,11 @@ anyio==4.4.0
|
||||
# via httpx
|
||||
auditwheel-emscripten==0.0.16
|
||||
# via pyodide-build
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via
|
||||
# -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||
# pyodide-build
|
||||
certifi==2024.7.4
|
||||
certifi==2024.8.30
|
||||
# via
|
||||
# httpcore
|
||||
# httpx
|
||||
@@ -21,19 +21,19 @@ click==8.1.7
|
||||
# via typer
|
||||
cloudpickle==3.0.0
|
||||
# via loky
|
||||
cmake==3.30.1
|
||||
cmake==3.30.3
|
||||
# via pyodide-build
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
h11==0.14.0
|
||||
# via httpcore
|
||||
httpcore==1.0.5
|
||||
# via httpx
|
||||
httpx==0.27.0
|
||||
httpx==0.27.2
|
||||
# via unearth
|
||||
idna==3.7
|
||||
idna==3.8
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
@@ -54,13 +54,13 @@ packaging==24.1
|
||||
# unearth
|
||||
pip==24.2
|
||||
# via -r .nox/update_constraints/tmp/constraints-pyodide.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pydantic==2.8.2
|
||||
pydantic==2.9.0
|
||||
# via
|
||||
# pyodide-build
|
||||
# pyodide-lock
|
||||
pydantic-core==2.20.1
|
||||
pydantic-core==2.23.2
|
||||
# via pydantic
|
||||
pygments==2.18.0
|
||||
# via rich
|
||||
@@ -74,13 +74,13 @@ pyodide-lock==0.1.0a6
|
||||
# via pyodide-build
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
pyyaml==6.0.1
|
||||
pyyaml==6.0.2
|
||||
# via pyodide-build
|
||||
requests==2.32.3
|
||||
# via pyodide-build
|
||||
resolvelib==1.0.1
|
||||
# via pyodide-build
|
||||
rich==13.7.1
|
||||
rich==13.8.0
|
||||
# via
|
||||
# pyodide-build
|
||||
# pyodide-cli
|
||||
@@ -95,29 +95,31 @@ sniffio==1.3.1
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
typer==0.12.3
|
||||
typer==0.12.5
|
||||
# via
|
||||
# auditwheel-emscripten
|
||||
# pyodide-build
|
||||
# pyodide-cli
|
||||
types-requests==2.32.0.20240712
|
||||
types-requests==2.32.0.20240907
|
||||
# via pyodide-build
|
||||
typing-extensions==4.12.2
|
||||
# via
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
# typer
|
||||
unearth==0.16.1
|
||||
tzdata==2024.1
|
||||
# via pydantic
|
||||
unearth==0.17.2
|
||||
# via pyodide-build
|
||||
urllib3==2.2.2
|
||||
# via
|
||||
# requests
|
||||
# types-requests
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via
|
||||
# build
|
||||
# pyodide-build
|
||||
wheel==0.43.0
|
||||
wheel==0.44.0
|
||||
# via
|
||||
# auditwheel-emscripten
|
||||
# pyodide-build
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
importlib-metadata==8.2.0
|
||||
importlib-metadata==8.4.0
|
||||
# via build
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -20,7 +20,7 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
@@ -28,7 +28,7 @@ tomli==2.0.1
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
zipp==3.19.2
|
||||
zipp==3.20.1
|
||||
# via importlib-metadata
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -18,11 +18,11 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -18,11 +18,11 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -18,11 +18,11 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -4,7 +4,7 @@ altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.1.1
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
@@ -33,7 +33,7 @@ typing-extensions==4.7.1
|
||||
# delocate
|
||||
# importlib-metadata
|
||||
# platformdirs
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
zipp==3.15.0
|
||||
# via importlib-metadata
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
importlib-metadata==8.2.0
|
||||
importlib-metadata==8.4.0
|
||||
# via build
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -20,7 +20,7 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
@@ -28,7 +28,7 @@ tomli==2.0.1
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
zipp==3.19.2
|
||||
zipp==3.20.1
|
||||
# via importlib-metadata
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
importlib-metadata==8.2.0
|
||||
importlib-metadata==8.4.0
|
||||
# via build
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -20,7 +20,7 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
@@ -28,7 +28,7 @@ tomli==2.0.1
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
zipp==3.19.2
|
||||
zipp==3.20.1
|
||||
# via importlib-metadata
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# nox -s update_constraints
|
||||
altgraph==0.17.4
|
||||
# via macholib
|
||||
build==1.2.1
|
||||
build==1.2.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
delocate==0.11.0
|
||||
delocate==0.12.0
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
distlib==0.3.8
|
||||
# via virtualenv
|
||||
filelock==3.15.4
|
||||
filelock==3.16.0
|
||||
# via virtualenv
|
||||
macholib==1.16.3
|
||||
# via delocate
|
||||
@@ -18,11 +18,11 @@ packaging==24.1
|
||||
# delocate
|
||||
pip==24.2
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
platformdirs==4.2.2
|
||||
platformdirs==4.3.2
|
||||
# via virtualenv
|
||||
pyproject-hooks==1.1.0
|
||||
# via build
|
||||
typing-extensions==4.12.2
|
||||
# via delocate
|
||||
virtualenv==20.26.3
|
||||
virtualenv==20.26.4
|
||||
# via -r cibuildwheel/resources/constraints.in
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
url = "https://nodejs.org/dist/"
|
||||
v20 = "v20.16.0"
|
||||
v20 = "v20.17.0"
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
[x86_64]
|
||||
manylinux1 = quay.io/pypa/manylinux1_x86_64:2024-04-29-76807b8
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.08.03-1
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.08.03-1
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.09.09-0
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2024.09.09-0
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_x86_64:2024.09.09-0
|
||||
|
||||
[i686]
|
||||
manylinux1 = quay.io/pypa/manylinux1_i686:2024-04-29-76807b8
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2024.08.03-1
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.08.03-1
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2024.09.09-0
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_i686:2024.09.09-0
|
||||
|
||||
[pypy_x86_64]
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2024.09.09-0
|
||||
|
||||
[pypy_i686]
|
||||
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_i686:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-12-26-0d38463
|
||||
|
||||
[aarch64]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.08.03-1
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.08.03-1
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.09-0
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2024.09.09-0
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_aarch64:2024.09.09-0
|
||||
|
||||
[ppc64le]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2024.08.03-1
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.08.03-1
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2024.09.09-0
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2024.09.09-0
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_ppc64le:2024.09.09-0
|
||||
|
||||
[s390x]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2024.08.03-1
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.08.03-1
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2024.09.09-0
|
||||
musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2024.09.09-0
|
||||
musllinux_1_2 = quay.io/pypa/musllinux_1_2_s390x:2024.09.09-0
|
||||
|
||||
[pypy_aarch64]
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.08.03-1
|
||||
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2024.09.09-0
|
||||
manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-12-26-0d38463
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.08.03-1
|
||||
manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2024.09.09-0
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
py36 = { version = "20.21.1", url = "https://github.com/pypa/get-virtualenv/blob/20.21.1/public/virtualenv.pyz?raw=true" }
|
||||
default = { version = "20.26.3", url = "https://github.com/pypa/get-virtualenv/blob/20.26.3/public/virtualenv.pyz?raw=true" }
|
||||
default = { version = "20.26.4", url = "https://github.com/pypa/get-virtualenv/blob/20.26.4/public/virtualenv.pyz?raw=true" }
|
||||
|
||||
@@ -4,8 +4,22 @@ title: Changelog
|
||||
|
||||
# Changelog
|
||||
|
||||
### v2.21.0
|
||||
|
||||
_13 September 2024_
|
||||
|
||||
- ⚠️ Update CPython 3.12 to 3.12.6, which changes the macOS minimum deployment target on CPython 3.12 from macOS 10.9 to macOS 10.13 (#1998)
|
||||
- 🛠 Changes the behaviour when inheriting `config-settings` in TOML overrides - rather than extending each key, which is rarely useful, individual keys will override previously set values. (#1803)
|
||||
- 🛠 Update CPython 3.13 to 3.13.0rc2 (#1998)
|
||||
- ✨ Adds support for multiarch OCI images (#1961)
|
||||
- 🐛 Fixes some bugs building Linux wheels on macOS. (#1961)
|
||||
- ⚠️ Changes the minimum version of Docker/Podman to Docker API version 1.43, Podman API version 3. The only mainstream runner this should affect is Travis Graviton2 runners - if so you can [upgrade your version of Docker](https://github.com/pypa/cibuildwheel/pull/1961#issuecomment-2304060019). (#1961)
|
||||
|
||||
|
||||
### v2.20.0
|
||||
|
||||
_4 August 2024_
|
||||
|
||||
- 🌟 CPython 3.13 wheels are now built by default - without the `CIBW_PRERELEASE_PYTHONS` flag. It's time to build and upload these wheels to PyPI! This release includes CPython 3.13.0rc1, which is guaranteed to be ABI compatible with the final release. Free-threading is still behind a flag/config option. (#1950)
|
||||
- ✨ Provide a `CIBW_ALLOW_EMPTY` environment variable as an alternative to the command line flag. (#1937)
|
||||
- 🐛 Don't use uv on PyPy3.8 on Windows, it stopped working starting in 0.2.25. Note that PyPy 3.8 is EoL. (#1868)
|
||||
@@ -16,6 +30,8 @@ title: Changelog
|
||||
|
||||
### v2.19.2
|
||||
|
||||
_2 July 2024_
|
||||
|
||||
- 🐛 Update manylinux2014 pins to versions that support past-EoL CentOS 7 mirrors. (#1917)
|
||||
- 🐛 Support `--no-isolation` with `build[uv]` build-frontend. (#1889)
|
||||
- 🛠 Provide attestations for releases at <https://github.com/pypa/cibuildwheel/attestations>. (#1916)
|
||||
@@ -28,6 +44,8 @@ title: Changelog
|
||||
|
||||
### v2.19.1
|
||||
|
||||
_13 June 2024_
|
||||
|
||||
- 🐛 Don't require setup-python on GHA for Pyodide (#1868)
|
||||
- 🐛 Specify full python path for uv (fixes issue in 0.2.10 & 0.2.11) (#1881)
|
||||
- 🛠 Update for pip 24.1b2 on CPython 3.13. (#1879)
|
||||
@@ -37,6 +55,8 @@ title: Changelog
|
||||
|
||||
### v2.19.0
|
||||
|
||||
_10 June 2024_
|
||||
|
||||
See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more info on new features!
|
||||
|
||||
- 🌟 Add Pyodide platform. Set with `--platform pyodide` or `CIBW_PLATFORM: pyodide` on Linux with a host Python 3.12 to build WebAssembly wheels. Not accepted on PyPI currently, but usable directly in a website using Pyodide, for live docs, etc. (#1456, #1859)
|
||||
@@ -55,6 +75,8 @@ See the [release post](https://iscinumpy.dev/post/cibuildwheel-2-19-0/) for more
|
||||
|
||||
### v2.18.1
|
||||
|
||||
_20 May 2024_
|
||||
|
||||
- 🌟 Add free-threaded Linux and Windows builds for 3.13. New identifiers `cp313t-*`, new option `CIBW_FREE_THREADED_SUPPORT`/`tool.cibuildwheel.free-threaded-support` required to opt-in. [See the docs](https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support) for more information. (#1831)
|
||||
- ✨ The `container-engine` is now a build (non-global) option. (#1792)
|
||||
- 🛠 The build backend for cibuildwheel is now hatchling. (#1297)
|
||||
|
||||
+3
-3
@@ -142,7 +142,7 @@ There are two suggested methods for keeping cibuildwheel up to date that instead
|
||||
If you use GitHub Actions for builds, you can use cibuildwheel as an action:
|
||||
|
||||
```yaml
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
uses: pypa/cibuildwheel@v2.21.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.
|
||||
@@ -164,7 +164,7 @@ The second option, and the only one that supports other CI systems, is using a `
|
||||
|
||||
```bash
|
||||
# requirements-cibw.txt
|
||||
cibuildwheel==2.20.0
|
||||
cibuildwheel==2.21.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:
|
||||
@@ -328,7 +328,7 @@ Solutions to this vary, but the simplest is to use pipx:
|
||||
# most runners have pipx preinstalled, but in case you don't
|
||||
python3 -m pip install pipx
|
||||
|
||||
pipx run cibuildwheel==2.20.0 --output-dir wheelhouse
|
||||
pipx run cibuildwheel==2.21.0 --output-dir wheelhouse
|
||||
pipx run twine upload wheelhouse/*.whl
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -161,7 +161,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheels
|
||||
run: pipx run cibuildwheel==2.20.0
|
||||
run: pipx run cibuildwheel==2.21.0
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -198,7 +198,7 @@ To build Linux, Mac, and Windows wheels using GitHub Actions, create a `.github/
|
||||
- uses: actions/setup-python@v5
|
||||
|
||||
- name: Install cibuildwheel
|
||||
run: python -m pip install cibuildwheel==2.20.0
|
||||
run: python -m pip install cibuildwheel==2.21.0
|
||||
|
||||
- name: Build wheels
|
||||
run: python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
+12
-12
@@ -11,8 +11,8 @@ title: Working examples
|
||||
| [scikit-learn][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The machine learning library. A complex but clean config using many of cibuildwheel's features to build a large project with Cython and C++ extensions. |
|
||||
| [pytorch-fairseq][] | ![github icon][] | ![apple icon][] ![linux icon][] | Facebook AI Research Sequence-to-Sequence Toolkit written in Python. |
|
||||
| [NumPy][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The fundamental package for scientific computing with Python. |
|
||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||
| [duckdb][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | DuckDB is an analytical in-process SQL database management system |
|
||||
| [Tornado][] | ![github icon][] | ![linux icon][] ![apple icon][] ![windows icon][] | Tornado is a Python web framework and asynchronous networking library. Uses stable ABI for a small C extension. |
|
||||
| [NCNN][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | ncnn is a high-performance neural network inference framework optimized for the mobile platform |
|
||||
| [Matplotlib][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The venerable Matplotlib, a Python library with C++ portions |
|
||||
| [Prophet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Tool for producing high quality forecasts for time series data that has multiple seasonality with linear or non-linear growth. |
|
||||
@@ -55,9 +55,9 @@ title: Working examples
|
||||
| [Wrapt][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python module for decorators, wrappers and monkey patching. |
|
||||
| [envd][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A machine learning development environment build tool |
|
||||
| [OpenColorIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | A color management framework for visual effects and animation. |
|
||||
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
|
||||
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
|
||||
| [Psycopg 3][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A modern implementation of a PostgreSQL adapter for Python |
|
||||
| [aioquic][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | QUIC and HTTP/3 implementation in Python |
|
||||
| [SimpleJSON][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | simplejson is a simple, fast, extensible JSON encoder/decoder for Python |
|
||||
| [ruptures][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Extensive Cython + NumPy [pyproject.toml](https://github.com/deepcharles/ruptures/blob/master/pyproject.toml) example. |
|
||||
| [OpenTimelineIO][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Open Source API and interchange format for editorial timeline information. |
|
||||
| [PyTables][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A Python package to manage extremely large amounts of data |
|
||||
@@ -93,8 +93,8 @@ title: Working examples
|
||||
| [streaming-form-data][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Streaming parser for multipart/form-data written in Cython |
|
||||
| [bx-python][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | A library that includes Cython extensions. |
|
||||
| [boost-histogram][] | ![github icon][] ![travisci icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Supports full range of wheels, including PyPy and alternate archs. |
|
||||
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
|
||||
| [power-grid-model][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python/C++ library for distribution power system analysis |
|
||||
| [Python-WebRTC][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | a Python extension that provides bindings to WebRTC M92 |
|
||||
| [pybase64][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Fast Base64 encoding/decoding in Python |
|
||||
| [Imagecodecs (fork)][] | ![azurepipelines icon][] | ![apple icon][] ![linux icon][] | Over 20 external dependencies in compiled libraries, custom docker image, `libomp`, `openblas` and `install_name_tool` for macOS. |
|
||||
| [fathon][] | ![travisci icon][] | ![apple icon][] ![linux icon][] | python package for DFA (Detrended Fluctuation Analysis) and related algorithms |
|
||||
@@ -103,14 +103,14 @@ title: Working examples
|
||||
| [polaroid][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Full range of wheels for setuptools rust, with auto release and PyPI deploy. |
|
||||
| [clang-format][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Scikit-build wrapper around LLVM's CMake, all platforms, generic wheels. |
|
||||
| [etebase-py][] | ![travisci icon][] | ![linux icon][] | Python bindings to a Rust library using `setuptools-rust`, and `sccache` for improved speed. |
|
||||
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
|
||||
| [cf-units][] | ![github icon][] | ![apple icon][] ![linux icon][] | Units of measure as required by the Climate and Forecast (CF) Metadata Conventions |
|
||||
| [ninja][] | ![github icon][] ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Multitagged binary builds for all supported platforms, using cibw 2 config configuration. |
|
||||
| [numpythia][] | ![github icon][] | ![apple icon][] ![linux icon][] | The interface between PYTHIA and NumPy |
|
||||
| [Confluent client for Kafka][] | ![travisci icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | setup in `tools/wheels/build-wheels.bat` |
|
||||
| [pyjet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | The interface between FastJet and NumPy |
|
||||
| [ril][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | A python binding to Rust Imaging library using maturin and Pyo3, utilizes Github Action cache to improve speed. Builds abi3 wheels. |
|
||||
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
|
||||
| [SiPM][] | ![github icon][] | ![apple icon][] ![linux icon][] | High performance library for SiPM detectors simulation using C++17, OpenMP and AVX2 intrinsics. |
|
||||
| [GSD][] | ![github icon][] | ![apple icon][] ![linux icon][] ![windows icon][] | Cython and NumPy project with 64-bit wheels. |
|
||||
| [aalink][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Async Python interface for Ableton Link. |
|
||||
| [CorrectionLib][] | ![github icon][] | ![apple icon][] ![linux icon][] | Structured JSON powered correction library for HEP, designed for the CMS experiment at CERN. |
|
||||
| [xmlstarlet][] | ![github icon][] | ![windows icon][] ![apple icon][] ![linux icon][] | Python 3.6+ CFFI bindings with true MSVC build. |
|
||||
@@ -121,8 +121,8 @@ title: Working examples
|
||||
[scikit-learn]: https://github.com/scikit-learn/scikit-learn
|
||||
[pytorch-fairseq]: https://github.com/facebookresearch/fairseq
|
||||
[NumPy]: https://github.com/numpy/numpy
|
||||
[Tornado]: https://github.com/tornadoweb/tornado
|
||||
[duckdb]: https://github.com/duckdb/duckdb
|
||||
[Tornado]: https://github.com/tornadoweb/tornado
|
||||
[NCNN]: https://github.com/Tencent/ncnn
|
||||
[Matplotlib]: https://github.com/matplotlib/matplotlib
|
||||
[Prophet]: https://github.com/facebook/prophet
|
||||
@@ -165,9 +165,9 @@ title: Working examples
|
||||
[Wrapt]: https://github.com/GrahamDumpleton/wrapt
|
||||
[envd]: https://github.com/tensorchord/envd
|
||||
[OpenColorIO]: https://github.com/AcademySoftwareFoundation/OpenColorIO
|
||||
[SimpleJSON]: https://github.com/simplejson/simplejson
|
||||
[aioquic]: https://github.com/aiortc/aioquic
|
||||
[Psycopg 3]: https://github.com/psycopg/psycopg
|
||||
[aioquic]: https://github.com/aiortc/aioquic
|
||||
[SimpleJSON]: https://github.com/simplejson/simplejson
|
||||
[ruptures]: https://github.com/deepcharles/ruptures
|
||||
[OpenTimelineIO]: https://github.com/AcademySoftwareFoundation/OpenTimelineIO
|
||||
[PyTables]: https://github.com/PyTables/PyTables
|
||||
@@ -203,8 +203,8 @@ title: Working examples
|
||||
[streaming-form-data]: https://github.com/siddhantgoel/streaming-form-data
|
||||
[bx-python]: https://github.com/bxlab/bx-python
|
||||
[boost-histogram]: https://github.com/scikit-hep/boost-histogram
|
||||
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
|
||||
[power-grid-model]: https://github.com/PowerGridModel/power-grid-model
|
||||
[Python-WebRTC]: https://github.com/MarshalX/python-webrtc
|
||||
[pybase64]: https://github.com/mayeut/pybase64
|
||||
[Imagecodecs (fork)]: https://github.com/czaki/imagecodecs_build
|
||||
[fathon]: https://github.com/stfbnc/fathon
|
||||
@@ -213,14 +213,14 @@ title: Working examples
|
||||
[polaroid]: https://github.com/daggy1234/polaroid
|
||||
[clang-format]: https://github.com/ssciwr/clang-format-wheel
|
||||
[etebase-py]: https://github.com/etesync/etebase-py
|
||||
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
|
||||
[cf-units]: https://github.com/SciTools/cf-units
|
||||
[ninja]: https://github.com/scikit-build/ninja-python-distributions
|
||||
[numpythia]: https://github.com/scikit-hep/numpythia
|
||||
[Confluent client for Kafka]: https://github.com/confluentinc/confluent-kafka-python
|
||||
[pyjet]: https://github.com/scikit-hep/pyjet
|
||||
[ril]: https://github.com/Cryptex-github/ril-py
|
||||
[GSD]: https://github.com/glotzerlab/gsd
|
||||
[SiPM]: https://github.com/EdoPro98/SimSiPM
|
||||
[GSD]: https://github.com/glotzerlab/gsd
|
||||
[aalink]: https://github.com/artfwo/aalink
|
||||
[CorrectionLib]: https://github.com/cms-nanoAOD/correctionlib
|
||||
[xmlstarlet]: https://github.com/dimitern/xmlstarlet
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
|
||||
APPVEYOR_JOB_NAME: "python37-x64-ubuntu"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
APPVEYOR_JOB_NAME: "python37-x64-vs2015"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos
|
||||
APPVEYOR_JOB_NAME: "python37-x64-macos"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu2204
|
||||
APPVEYOR_JOB_NAME: "linux-x64"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
APPVEYOR_JOB_NAME: "windows-x64"
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: macos-sonoma
|
||||
APPVEYOR_JOB_NAME: "macos-x64"
|
||||
|
||||
stack: python 3.7
|
||||
stack: python 3.12
|
||||
|
||||
init:
|
||||
- cmd: set PATH=C:\Python37;C:\Python37\Scripts;%PATH%
|
||||
|
||||
install: python -m pip install cibuildwheel==2.20.0
|
||||
install: python -m pip install cibuildwheel==2.21.0
|
||||
|
||||
build_script: python -m cibuildwheel --output-dir wheelhouse
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python3 -m pip install --upgrade pip
|
||||
pip3 install cibuildwheel==2.20.0
|
||||
pip3 install cibuildwheel==2.21.0
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install cibuildwheel==2.20.0
|
||||
python3 -m pip install cibuildwheel==2.21.0
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
- bash: |
|
||||
set -o errexit
|
||||
python -m pip install --upgrade pip
|
||||
pip install cibuildwheel==2.20.0
|
||||
pip install cibuildwheel==2.21.0
|
||||
displayName: Install dependencies
|
||||
- bash: cibuildwheel --output-dir wheelhouse .
|
||||
displayName: Build wheels
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the Linux wheels.
|
||||
command: |
|
||||
python3 -m pip install --user cibuildwheel==2.20.0
|
||||
python3 -m pip install --user cibuildwheel==2.21.0
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
- run:
|
||||
name: Build the Linux aarch64 wheels.
|
||||
command: |
|
||||
python3 -m pip install --user cibuildwheel==2.20.0
|
||||
python3 -m pip install --user cibuildwheel==2.21.0
|
||||
python3 -m cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
name: Build the OS X wheels.
|
||||
command: |
|
||||
sudo softwareupdate --install-rosetta --agree-to-license # for python<=3.8 or x86_64/universal2 tests
|
||||
pip3 install cibuildwheel==2.20.0
|
||||
pip3 install cibuildwheel==2.21.0
|
||||
cibuildwheel --output-dir wheelhouse
|
||||
- store_artifacts:
|
||||
path: wheelhouse/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
||||
install_cibuildwheel_script:
|
||||
- python -m pip install cibuildwheel==2.20.0
|
||||
- python -m pip install cibuildwheel==2.21.0
|
||||
run_cibuildwheel_script:
|
||||
- cibuildwheel
|
||||
wheels_artifacts:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
build_and_store_wheels: &BUILD_AND_STORE_WHEELS
|
||||
install_cibuildwheel_script:
|
||||
- python -m pip install cibuildwheel==2.20.0
|
||||
- python -m pip install cibuildwheel==2.21.0
|
||||
run_cibuildwheel_script:
|
||||
- cibuildwheel
|
||||
wheels_artifacts:
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
uses: pypa/cibuildwheel@v2.21.0
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
uses: pypa/cibuildwheel@v2.21.0
|
||||
# env:
|
||||
# CIBW_SOME_OPTION: value
|
||||
# ...
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
platforms: all
|
||||
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
uses: pypa/cibuildwheel@v2.21.0
|
||||
env:
|
||||
# configure cibuildwheel to build native archs ('auto'), and some
|
||||
# emulated ones
|
||||
|
||||
@@ -12,7 +12,7 @@ linux:
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
script:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
- python -m pip install cibuildwheel==2.20.0
|
||||
- python -m pip install cibuildwheel==2.21.0
|
||||
- cibuildwheel --output-dir wheelhouse
|
||||
artifacts:
|
||||
paths:
|
||||
@@ -23,7 +23,7 @@ windows:
|
||||
before_script:
|
||||
- choco install python -y --version 3.12.4
|
||||
- choco install git.install -y
|
||||
- py -m pip install cibuildwheel==2.20.0
|
||||
- py -m pip install cibuildwheel==2.21.0
|
||||
script:
|
||||
- py -m cibuildwheel --output-dir wheelhouse --platform windows
|
||||
artifacts:
|
||||
@@ -35,7 +35,7 @@ windows:
|
||||
macos:
|
||||
image: macos-14-xcode-15
|
||||
before_script:
|
||||
- python3 -m pip install cibuildwheel==2.20.0
|
||||
- python3 -m pip install cibuildwheel==2.21.0
|
||||
script:
|
||||
- python3 -m cibuildwheel --output-dir wheelhouse
|
||||
artifacts:
|
||||
|
||||
@@ -14,7 +14,7 @@ linux:
|
||||
- curl -sSL https://get.docker.com/ | sh
|
||||
# Warning: This is extremely slow, be careful with how many wheels you build
|
||||
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
- python -m pip install cibuildwheel==2.20.0
|
||||
- python -m pip install cibuildwheel==2.21.0
|
||||
# Assuming your CI runner's default architecture is x86_64...
|
||||
- cibuildwheel --output-dir wheelhouse --platform linux --archs aarch64
|
||||
artifacts:
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==2.20.0
|
||||
- python3 -m pip install cibuildwheel==2.21.0
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './dist'
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- ln -s /c/Python312/python.exe /c/Python312/python3.exe
|
||||
|
||||
install:
|
||||
- python3 -m pip install cibuildwheel==2.20.0
|
||||
- python3 -m pip install cibuildwheel==2.21.0
|
||||
|
||||
script:
|
||||
# build the wheels, put them into './wheelhouse'
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
- stage: deploy
|
||||
name: Build and deploy Linux wheels
|
||||
services: docker
|
||||
install: python3 -m pip install cibuildwheel==2.20.0 twine
|
||||
install: python3 -m pip install cibuildwheel==2.21.0 twine
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
||||
# Deploy on windows
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
name: Build and deploy Windows wheels
|
||||
os: windows
|
||||
language: shell
|
||||
install: python3 -m pip install cibuildwheel==2.20.0 twine
|
||||
install: python3 -m pip install cibuildwheel==2.21.0 twine
|
||||
script: python3 -m cibuildwheel --output-dir wheelhouse
|
||||
after_success: python3 -m twine upload --skip-existing wheelhouse/*.whl
|
||||
|
||||
|
||||
+1
-3
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "cibuildwheel"
|
||||
version = "2.20.0"
|
||||
version = "2.21.0"
|
||||
description = "Build Python wheels on CI with minimal configuration."
|
||||
readme = "README.md"
|
||||
license = "BSD-2-Clause"
|
||||
@@ -184,10 +184,8 @@ messages_control.disable = [
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py38"
|
||||
line-length = 100
|
||||
|
||||
|
||||
[tool.ruff.lint]
|
||||
extend-select = [
|
||||
"B", # flake8-bugbear
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
|
||||
return {"CIBW_BUILD_FRONTEND": frontend}
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str]:
|
||||
frontend = build_frontend_env_nouv["CIBW_BUILD_FRONTEND"]
|
||||
if frontend != "build" or platform == "pyodide" or find_uv() is None:
|
||||
@@ -46,7 +46,7 @@ def build_frontend_env(build_frontend_env_nouv: dict[str, str]) -> dict[str, str
|
||||
return {"CIBW_BUILD_FRONTEND": "build[uv]"}
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def docker_cleanup() -> Generator[None, None, None]:
|
||||
def get_images() -> set[str]:
|
||||
if detect_ci_provider() is None or platform != "linux":
|
||||
|
||||
@@ -21,7 +21,7 @@ def test_podman(tmp_path, capfd, request):
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
"CIBW_ARCHS": "x86_64",
|
||||
"CIBW_ARCHS": "native",
|
||||
"CIBW_BEFORE_ALL": "echo 'test log statement from before-all'",
|
||||
"CIBW_CONTAINER_ENGINE": "podman",
|
||||
},
|
||||
@@ -29,9 +29,7 @@ def test_podman(tmp_path, capfd, request):
|
||||
)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels("spam", "0.1.0", single_python=True) if "x86_64" in w
|
||||
]
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0", single_python=True, single_arch=True)
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
# check that stdout is bring passed-though from container correctly
|
||||
|
||||
@@ -6,7 +6,7 @@ import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.util import CIBW_CACHE_PATH
|
||||
from cibuildwheel.util import CIBW_CACHE_PATH, CIProvider, detect_ci_provider
|
||||
|
||||
from . import test_projects, utils
|
||||
|
||||
@@ -49,6 +49,9 @@ def test_pyodide_build(tmp_path, use_pyproject_toml):
|
||||
if not shutil.which("python3.12"):
|
||||
pytest.skip("Python 3.12 not installed")
|
||||
|
||||
if detect_ci_provider() == CIProvider.travis_ci:
|
||||
pytest.skip("Python 3.12 is just a non-working pyenv shim")
|
||||
|
||||
if use_pyproject_toml:
|
||||
basic_project.files["pyproject.toml"] = textwrap.dedent(
|
||||
"""
|
||||
|
||||
+20
-19
@@ -23,15 +23,14 @@ EMULATED_ARCHS: Final[list[str]] = sorted(
|
||||
)
|
||||
SINGLE_PYTHON_VERSION: Final[tuple[int, int]] = (3, 12)
|
||||
|
||||
platform: str
|
||||
|
||||
if "CIBW_PLATFORM" in os.environ:
|
||||
platform = os.environ["CIBW_PLATFORM"]
|
||||
platform = os.environ.get("CIBW_PLATFORM", "")
|
||||
if platform:
|
||||
pass
|
||||
elif sys.platform.startswith("linux"):
|
||||
platform = "linux"
|
||||
elif sys.platform.startswith("darwin"):
|
||||
platform = "macos"
|
||||
elif sys.platform in ["win32", "cygwin"]:
|
||||
elif sys.platform.startswith(("win32", "cygwin")):
|
||||
platform = "windows"
|
||||
else:
|
||||
msg = f"Unsupported platform {sys.platform!r}"
|
||||
@@ -275,25 +274,27 @@ def expected_wheels(
|
||||
platform_tags = ["win32", "win_amd64"]
|
||||
|
||||
elif platform == "macos":
|
||||
if python_abi_tag.startswith("pp"):
|
||||
if python_abi_tag.startswith(("pp37", "pp38")):
|
||||
min_macosx = macosx_deployment_target
|
||||
else:
|
||||
min_macosx = _floor_macosx(macosx_deployment_target, "10.15")
|
||||
elif python_abi_tag.startswith("cp"):
|
||||
if python_abi_tag.startswith(("cp36", "cp37", "cp38", "cp39", "cp310", "cp311")):
|
||||
min_macosx = macosx_deployment_target
|
||||
else:
|
||||
min_macosx = _floor_macosx(macosx_deployment_target, "10.13")
|
||||
else:
|
||||
min_macosx = macosx_deployment_target
|
||||
|
||||
if machine_arch == "arm64":
|
||||
arm64_macosx = _floor_macosx(macosx_deployment_target, "11.0")
|
||||
arm64_macosx = _floor_macosx(min_macosx, "11.0")
|
||||
platform_tags = [f'macosx_{arm64_macosx.replace(".", "_")}_arm64']
|
||||
else:
|
||||
if python_abi_tag.startswith("pp") and not python_abi_tag.startswith(
|
||||
("pp37", "pp38")
|
||||
):
|
||||
pypy_macosx = _floor_macosx(macosx_deployment_target, "10.15")
|
||||
platform_tags = [f'macosx_{pypy_macosx.replace(".", "_")}_x86_64']
|
||||
elif python_abi_tag.startswith("cp313"):
|
||||
pypy_macosx = _floor_macosx(macosx_deployment_target, "10.13")
|
||||
platform_tags = [f'macosx_{pypy_macosx.replace(".", "_")}_x86_64']
|
||||
else:
|
||||
platform_tags = [f'macosx_{macosx_deployment_target.replace(".", "_")}_x86_64']
|
||||
platform_tags = [f'macosx_{min_macosx.replace(".", "_")}_x86_64']
|
||||
|
||||
if include_universal2:
|
||||
platform_tags.append(
|
||||
f'macosx_{macosx_deployment_target.replace(".", "_")}_universal2',
|
||||
)
|
||||
platform_tags.append(f'macosx_{min_macosx.replace(".", "_")}_universal2')
|
||||
else:
|
||||
msg = f"Unsupported platform {platform!r}"
|
||||
raise Exception(msg)
|
||||
|
||||
@@ -19,7 +19,7 @@ def pytest_addoption(parser):
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def fake_package_dir(tmp_path, monkeypatch):
|
||||
"""
|
||||
Monkey-patch enough for the main() function to run
|
||||
|
||||
@@ -47,7 +47,7 @@ def mock_protection(monkeypatch):
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def fake_package_dir_autouse(fake_package_dir): # noqa: ARG001
|
||||
def fake_package_dir_autouse(fake_package_dir):
|
||||
pass
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def disable_print_wheels(monkeypatch):
|
||||
monkeypatch.setattr(util, "print_new_wheels", empty_cm)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def allow_empty(monkeypatch, fake_package_dir):
|
||||
monkeypatch.setattr(sys, "argv", [*fake_package_dir, "--allow-empty"])
|
||||
|
||||
@@ -81,7 +81,7 @@ def platform(request, monkeypatch):
|
||||
return platform_value
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def intercepted_build_args(monkeypatch):
|
||||
intercepted = ArgsInterceptor()
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from cibuildwheel.architecture import Architecture
|
||||
from ..conftest import MOCK_PACKAGE_DIR
|
||||
|
||||
|
||||
@pytest.mark.parametrize("option_value", [None, "auto"])
|
||||
@pytest.mark.parametrize("option_value", [None, "auto", ""])
|
||||
def test_platform_unset_or_auto(monkeypatch, intercepted_build_args, option_value):
|
||||
if option_value is None:
|
||||
monkeypatch.delenv("CIBW_PLATFORM", raising=False)
|
||||
|
||||
+140
-26
@@ -6,6 +6,7 @@ import platform
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from pathlib import Path, PurePath, PurePosixPath
|
||||
|
||||
@@ -13,7 +14,7 @@ import pytest
|
||||
import tomli_w
|
||||
|
||||
from cibuildwheel.environment import EnvironmentAssignmentBash
|
||||
from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig
|
||||
from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
|
||||
from cibuildwheel.util import CIProvider, detect_ci_provider
|
||||
|
||||
# Test utilities
|
||||
@@ -28,6 +29,14 @@ elif pm in {"aarch64", "arm64"}:
|
||||
DEFAULT_IMAGE = DEFAULT_IMAGE_TEMPLATE.format(machine="aarch64")
|
||||
else:
|
||||
DEFAULT_IMAGE = ""
|
||||
DEFAULT_OCI_PLATFORM = {
|
||||
"AMD64": OCIPlatform.AMD64,
|
||||
"x86_64": OCIPlatform.AMD64,
|
||||
"ppc64le": OCIPlatform.PPC64LE,
|
||||
"s390x": OCIPlatform.S390X,
|
||||
"aarch64": OCIPlatform.ARM64,
|
||||
"arm64": OCIPlatform.ARM64,
|
||||
}[pm]
|
||||
|
||||
PODMAN = OCIContainerEngineConfig(name="podman")
|
||||
|
||||
@@ -63,24 +72,32 @@ def container_engine(request):
|
||||
|
||||
|
||||
def test_simple(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
assert container.call(["echo", "hello"], capture_output=True) == "hello\n"
|
||||
|
||||
|
||||
def test_no_lf(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
assert container.call(["printf", "hello"], capture_output=True) == "hello"
|
||||
|
||||
|
||||
def test_debug_info(container_engine):
|
||||
container = OCIContainer(engine=container_engine, image=DEFAULT_IMAGE)
|
||||
container = OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
)
|
||||
print(container.debug_info())
|
||||
with container:
|
||||
pass
|
||||
|
||||
|
||||
def test_environment(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
assert (
|
||||
container.call(
|
||||
["sh", "-c", "echo $TEST_VAR"], env={"TEST_VAR": "1"}, capture_output=True
|
||||
@@ -92,7 +109,9 @@ def test_environment(container_engine):
|
||||
def test_environment_pass(container_engine, monkeypatch):
|
||||
monkeypatch.setenv("CIBUILDWHEEL", "1")
|
||||
monkeypatch.setenv("SOURCE_DATE_EPOCH", "1489957071")
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
assert container.call(["sh", "-c", "echo $CIBUILDWHEEL"], capture_output=True) == "1\n"
|
||||
assert (
|
||||
container.call(["sh", "-c", "echo $SOURCE_DATE_EPOCH"], capture_output=True)
|
||||
@@ -102,14 +121,23 @@ def test_environment_pass(container_engine, monkeypatch):
|
||||
|
||||
def test_cwd(container_engine):
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, cwd="/cibuildwheel/working_directory"
|
||||
engine=container_engine,
|
||||
image=DEFAULT_IMAGE,
|
||||
oci_platform=DEFAULT_OCI_PLATFORM,
|
||||
cwd="/cibuildwheel/working_directory",
|
||||
) as container:
|
||||
assert container.call(["pwd"], capture_output=True) == "/cibuildwheel/working_directory\n"
|
||||
assert container.call(["pwd"], capture_output=True, cwd="/opt") == "/opt\n"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
pm == "s390x" and detect_ci_provider() == CIProvider.travis_ci,
|
||||
reason="test is flaky on this platform, see https://github.com/pypa/cibuildwheel/pull/1961#issuecomment-2334678966",
|
||||
)
|
||||
def test_container_removed(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
docker_containers_listing = subprocess.run(
|
||||
f"{container.engine.name} container ls",
|
||||
shell=True,
|
||||
@@ -141,7 +169,9 @@ def test_large_environment(container_engine):
|
||||
"d": "0" * long_env_var_length,
|
||||
}
|
||||
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
# check the length of d
|
||||
assert (
|
||||
container.call(["sh", "-c", "echo ${#d}"], env=large_environment, capture_output=True)
|
||||
@@ -150,7 +180,9 @@ def test_large_environment(container_engine):
|
||||
|
||||
|
||||
def test_binary_output(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
# note: the below embedded snippets are in python2
|
||||
|
||||
# check that we can pass though arbitrary binary data without erroring
|
||||
@@ -200,7 +232,9 @@ def test_binary_output(container_engine):
|
||||
|
||||
|
||||
def test_file_operation(tmp_path: Path, container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
# test copying a file in
|
||||
test_binary_data = bytes(random.randrange(256) for _ in range(1000))
|
||||
original_test_file = tmp_path / "test.dat"
|
||||
@@ -215,7 +249,9 @@ def test_file_operation(tmp_path: Path, container_engine):
|
||||
|
||||
|
||||
def test_dir_operations(tmp_path: Path, container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
test_binary_data = bytes(random.randrange(256) for _ in range(1000))
|
||||
original_test_file = tmp_path / "test.dat"
|
||||
original_test_file.write_bytes(test_binary_data)
|
||||
@@ -244,7 +280,9 @@ def test_dir_operations(tmp_path: Path, container_engine):
|
||||
|
||||
|
||||
def test_environment_executor(container_engine):
|
||||
with OCIContainer(engine=container_engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
assignment = EnvironmentAssignmentBash("TEST=$(echo 42)")
|
||||
assert assignment.evaluated_value({}, container.environment_executor) == "42"
|
||||
|
||||
@@ -252,6 +290,8 @@ def test_environment_executor(container_engine):
|
||||
def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
|
||||
if container_engine.name != "podman":
|
||||
pytest.skip("only runs with podman")
|
||||
if sys.platform.startswith("darwin"):
|
||||
pytest.skip("Skipping test because podman on this platform does not support vfs")
|
||||
|
||||
# create the VFS configuration
|
||||
vfs_path = tmp_path / "podman_vfs"
|
||||
@@ -309,7 +349,9 @@ def test_podman_vfs(tmp_path: Path, monkeypatch, container_engine):
|
||||
monkeypatch.setenv("CONTAINERS_CONF", str(vfs_containers_conf_fpath))
|
||||
monkeypatch.setenv("CONTAINERS_STORAGE_CONF", str(vfs_containers_storage_conf_fpath))
|
||||
|
||||
with OCIContainer(engine=PODMAN, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=PODMAN, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
# test running a command
|
||||
assert container.call(["echo", "hello"], capture_output=True) == "hello\n"
|
||||
|
||||
@@ -346,6 +388,7 @@ def test_create_args_volume(tmp_path: Path, container_engine):
|
||||
with OCIContainer(
|
||||
engine=container_engine,
|
||||
image=DEFAULT_IMAGE,
|
||||
oci_platform=DEFAULT_OCI_PLATFORM,
|
||||
) as container:
|
||||
assert container.call(["cat", "/test_mount/test_file.txt"], capture_output=True) == "1234"
|
||||
|
||||
@@ -388,24 +431,47 @@ def test_create_args_volume(tmp_path: Path, container_engine):
|
||||
"docker",
|
||||
("--some-option=value; with; semicolons", "--another-option"),
|
||||
),
|
||||
(
|
||||
"docker; create_args: --platform=linux/amd64",
|
||||
"docker",
|
||||
(),
|
||||
),
|
||||
(
|
||||
"podman; create_args: --platform=linux/amd64",
|
||||
"podman",
|
||||
(),
|
||||
),
|
||||
(
|
||||
"docker; create_args: --platform linux/amd64",
|
||||
"docker",
|
||||
(),
|
||||
),
|
||||
(
|
||||
"podman; create_args: --platform linux/amd64",
|
||||
"podman",
|
||||
(),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_parse_engine_config(config, name, create_args):
|
||||
def test_parse_engine_config(config, name, create_args, capsys):
|
||||
engine_config = OCIContainerEngineConfig.from_config_string(config)
|
||||
assert engine_config.name == name
|
||||
assert engine_config.create_args == create_args
|
||||
if "--platform" in config:
|
||||
captured = capsys.readouterr()
|
||||
assert (
|
||||
"Using '--platform' in 'container-engine::create_args' is deprecated. It will be ignored."
|
||||
in captured.err
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(pm != "x86_64", reason="Only runs on x86_64")
|
||||
@pytest.mark.parametrize(
|
||||
("image", "shell_args"),
|
||||
[
|
||||
(DEFAULT_IMAGE_TEMPLATE.format(machine="i686"), ["/bin/bash"]),
|
||||
(DEFAULT_IMAGE_TEMPLATE.format(machine="x86_64"), ["linux32", "/bin/bash"]),
|
||||
],
|
||||
)
|
||||
def test_enforce_32_bit(container_engine, image, shell_args):
|
||||
with OCIContainer(engine=container_engine, image=image, enforce_32_bit=True) as container:
|
||||
def test_enforce_32_bit(container_engine):
|
||||
with OCIContainer(
|
||||
engine=container_engine,
|
||||
image=DEFAULT_IMAGE_TEMPLATE.format(machine="i686"),
|
||||
oci_platform=OCIPlatform.i386,
|
||||
) as container:
|
||||
assert container.call(["uname", "-m"], capture_output=True).strip() == "i686"
|
||||
container_args = subprocess.run(
|
||||
f"{container.engine.name} inspect -f '{{{{json .Args }}}}' {container.name}",
|
||||
@@ -414,7 +480,7 @@ def test_enforce_32_bit(container_engine, image, shell_args):
|
||||
stdout=subprocess.PIPE,
|
||||
text=True,
|
||||
).stdout
|
||||
assert json.loads(container_args) == shell_args
|
||||
assert json.loads(container_args) == ["/bin/bash"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -428,16 +494,64 @@ def test_enforce_32_bit(container_engine, image, shell_args):
|
||||
def test_disable_host_mount(tmp_path: Path, container_engine, config, should_have_host_mount):
|
||||
if detect_ci_provider() in {CIProvider.circle_ci, CIProvider.gitlab}:
|
||||
pytest.skip("Skipping test because docker on this platform does not support host mounts")
|
||||
if sys.platform.startswith("darwin"):
|
||||
pytest.skip("Skipping test because docker on this platform does not support host mounts")
|
||||
|
||||
engine = OCIContainerEngineConfig.from_config_string(config.format(name=container_engine.name))
|
||||
|
||||
sentinel_file = tmp_path / "sentinel"
|
||||
sentinel_file.write_text("12345")
|
||||
|
||||
with OCIContainer(engine=engine, image=DEFAULT_IMAGE) as container:
|
||||
with OCIContainer(
|
||||
engine=engine, image=DEFAULT_IMAGE, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
) as container:
|
||||
host_mount_path = "/host" + str(sentinel_file)
|
||||
if should_have_host_mount:
|
||||
assert container.call(["cat", host_mount_path], capture_output=True) == "12345"
|
||||
else:
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
container.call(["cat", host_mount_path], capture_output=True)
|
||||
|
||||
|
||||
def test_local_image(container_engine):
|
||||
local_image = f"cibw_test_{container_engine.name}_local:latest"
|
||||
subprocess.run(
|
||||
[container_engine.name, "pull", f"--platform={DEFAULT_OCI_PLATFORM.value}", DEFAULT_IMAGE],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run([container_engine.name, "image", "tag", DEFAULT_IMAGE, local_image], check=True)
|
||||
with OCIContainer(
|
||||
engine=container_engine, image=local_image, oci_platform=DEFAULT_OCI_PLATFORM
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platform", list(OCIPlatform))
|
||||
def test_multiarch_image(container_engine, platform):
|
||||
if (
|
||||
detect_ci_provider() in {CIProvider.travis_ci}
|
||||
and pm in {"s390x", "ppc64le"}
|
||||
and platform != DEFAULT_OCI_PLATFORM
|
||||
):
|
||||
pytest.skip("Skipping test because docker on this platform does not support QEMU")
|
||||
with OCIContainer(
|
||||
engine=container_engine, image="debian:12-slim", oci_platform=platform
|
||||
) as container:
|
||||
output = container.call(["uname", "-m"], capture_output=True)
|
||||
output_map = {
|
||||
OCIPlatform.i386: "i686",
|
||||
OCIPlatform.AMD64: "x86_64",
|
||||
OCIPlatform.ARM64: "aarch64",
|
||||
OCIPlatform.PPC64LE: "ppc64le",
|
||||
OCIPlatform.S390X: "s390x",
|
||||
}
|
||||
assert output_map[platform] == output.strip()
|
||||
output = container.call(["dpkg", "--print-architecture"], capture_output=True)
|
||||
output_map = {
|
||||
OCIPlatform.i386: "i386",
|
||||
OCIPlatform.AMD64: "amd64",
|
||||
OCIPlatform.ARM64: "arm64",
|
||||
OCIPlatform.PPC64LE: "ppc64el",
|
||||
OCIPlatform.S390X: "s390x",
|
||||
}
|
||||
assert output_map[platform] == output.strip()
|
||||
|
||||
@@ -12,6 +12,7 @@ import pytest
|
||||
|
||||
from cibuildwheel import linux, util
|
||||
from cibuildwheel.__main__ import main
|
||||
from cibuildwheel.oci_container import OCIPlatform
|
||||
|
||||
ALL_IDS = {
|
||||
"cp36",
|
||||
@@ -29,7 +30,7 @@ ALL_IDS = {
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def mock_build_container(monkeypatch):
|
||||
def fail_on_call(*args, **kwargs):
|
||||
msg = "This should never be called"
|
||||
@@ -73,7 +74,7 @@ def test_build_default_launches(monkeypatch):
|
||||
kwargs = build_in_container.call_args_list[0][1]
|
||||
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {f"{x}-manylinux_x86_64" for x in ALL_IDS}
|
||||
@@ -81,7 +82,7 @@ def test_build_default_launches(monkeypatch):
|
||||
kwargs = build_in_container.call_args_list[1][1]
|
||||
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS}
|
||||
@@ -89,7 +90,7 @@ def test_build_default_launches(monkeypatch):
|
||||
kwargs = build_in_container.call_args_list[2][1]
|
||||
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {
|
||||
@@ -99,7 +100,7 @@ def test_build_default_launches(monkeypatch):
|
||||
kwargs = build_in_container.call_args_list[3][1]
|
||||
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x}
|
||||
@@ -142,7 +143,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[0][1]
|
||||
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {"cp36-manylinux_x86_64"}
|
||||
@@ -151,7 +152,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[1][1]
|
||||
assert "quay.io/pypa/manylinux2014_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {
|
||||
@@ -164,7 +165,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[2][1]
|
||||
assert "quay.io/pypa/manylinux_2_28_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {
|
||||
f"{x}-manylinux_x86_64"
|
||||
@@ -174,7 +175,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[3][1]
|
||||
assert "quay.io/pypa/manylinux2014_i686" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {f"{x}-manylinux_i686" for x in ALL_IDS}
|
||||
@@ -182,7 +183,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[4][1]
|
||||
assert "quay.io/pypa/musllinux_1_1_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {
|
||||
@@ -192,7 +193,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[5][1]
|
||||
assert "quay.io/pypa/musllinux_1_2_x86_64" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert not kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.AMD64
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {
|
||||
f"{x}-musllinux_x86_64" for x in ALL_IDS - {"cp36", "cp37", "cp38", "cp39"} if "pp" not in x
|
||||
@@ -201,7 +202,7 @@ before-all = "true"
|
||||
kwargs = build_in_container.call_args_list[6][1]
|
||||
assert "quay.io/pypa/musllinux_1_2_i686" in kwargs["container"]["image"]
|
||||
assert kwargs["container"]["cwd"] == PurePosixPath("/project")
|
||||
assert kwargs["container"]["enforce_32_bit"]
|
||||
assert kwargs["container"]["oci_platform"] == OCIPlatform.i386
|
||||
|
||||
identifiers = {x.identifier for x in kwargs["platform_configs"]}
|
||||
assert identifiers == {f"{x}-musllinux_i686" for x in ALL_IDS if "pp" not in x}
|
||||
|
||||
@@ -10,7 +10,6 @@ import pytest
|
||||
from cibuildwheel import errors
|
||||
from cibuildwheel.__main__ import get_build_identifiers, get_platform_module
|
||||
from cibuildwheel.bashlex_eval import local_environment_executor
|
||||
from cibuildwheel.environment import parse_environment
|
||||
from cibuildwheel.options import (
|
||||
CommandLineArguments,
|
||||
Options,
|
||||
@@ -66,7 +65,7 @@ def test_options_1(tmp_path, monkeypatch):
|
||||
|
||||
default_build_options = options.build_options(identifier=None)
|
||||
|
||||
assert default_build_options.environment == parse_environment('FOO="BAR"')
|
||||
assert default_build_options.environment.as_dictionary(prev_environment={}) == {"FOO": "BAR"}
|
||||
|
||||
all_pinned_container_images = _get_pinned_container_images()
|
||||
pinned_x86_64_container_image = all_pinned_container_images["x86_64"]
|
||||
|
||||
@@ -4,7 +4,15 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.options import ConfigOptionError, InheritRule, OptionsReader, _resolve_cascade
|
||||
from cibuildwheel.options import (
|
||||
EnvironmentFormat,
|
||||
InheritRule,
|
||||
ListFormat,
|
||||
OptionsReader,
|
||||
OptionsReaderError,
|
||||
ShlexTableFormat,
|
||||
_resolve_cascade,
|
||||
)
|
||||
|
||||
PYPROJECT_1 = """
|
||||
[tool.cibuildwheel]
|
||||
@@ -37,42 +45,32 @@ def test_simple_settings(tmp_path, platform, fname):
|
||||
|
||||
options_reader = OptionsReader(config_file_path, platform=platform, env={})
|
||||
|
||||
assert options_reader.get("build", env_plat=False, list_sep=" ") == "cp39*"
|
||||
assert options_reader.get("build", option_format=ListFormat(" "), env_plat=False) == "cp39*"
|
||||
|
||||
assert options_reader.get("test-command") == "pyproject"
|
||||
assert options_reader.get("archs", list_sep=" ") == "auto"
|
||||
assert options_reader.get("archs", option_format=ListFormat(" ")) == "auto"
|
||||
assert (
|
||||
options_reader.get("test-requires", list_sep=" ")
|
||||
options_reader.get("test-requires", option_format=ListFormat(" "))
|
||||
== {"windows": "something", "macos": "else", "linux": "other many"}[platform]
|
||||
)
|
||||
|
||||
# Also testing options for support for both lists and tables
|
||||
assert (
|
||||
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
|
||||
options_reader.get("environment", option_format=EnvironmentFormat())
|
||||
== 'THING="OTHER" FOO="BAR"'
|
||||
)
|
||||
assert (
|
||||
options_reader.get(
|
||||
"environment", list_sep="x", table_format={"item": '{k}="{v}"', "sep": " "}
|
||||
)
|
||||
== 'THING="OTHER" FOO="BAR"'
|
||||
)
|
||||
assert options_reader.get("test-extras", list_sep=",") == "one,two"
|
||||
assert (
|
||||
options_reader.get(
|
||||
"test-extras", list_sep=",", table_format={"item": '{k}="{v}"', "sep": " "}
|
||||
)
|
||||
== "one,two"
|
||||
)
|
||||
assert options_reader.get("test-extras", option_format=ListFormat(",")) == "one,two"
|
||||
|
||||
assert options_reader.get("manylinux-x86_64-image") == "manylinux1"
|
||||
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
|
||||
|
||||
with pytest.raises(ConfigOptionError):
|
||||
options_reader.get("environment", list_sep=" ")
|
||||
with pytest.raises(OptionsReaderError):
|
||||
# fails because the option is a table and the option_format only works with lists
|
||||
options_reader.get("environment", option_format=ListFormat(" "))
|
||||
|
||||
with pytest.raises(ConfigOptionError):
|
||||
options_reader.get("test-extras", table_format={"item": '{k}="{v}"', "sep": " "})
|
||||
with pytest.raises(OptionsReaderError):
|
||||
# fails because the option is a list and the option_format only works with tables
|
||||
options_reader.get("test-extras", option_format=ShlexTableFormat())
|
||||
|
||||
|
||||
def test_envvar_override(tmp_path, platform):
|
||||
@@ -91,14 +89,14 @@ def test_envvar_override(tmp_path, platform):
|
||||
},
|
||||
)
|
||||
|
||||
assert options_reader.get("archs", list_sep=" ") == "auto"
|
||||
assert options_reader.get("archs", option_format=ListFormat(" ")) == "auto"
|
||||
|
||||
assert options_reader.get("build", list_sep=" ") == "cp38*"
|
||||
assert options_reader.get("build") == "cp38*"
|
||||
assert options_reader.get("manylinux-x86_64-image") == "manylinux_2_24"
|
||||
assert options_reader.get("manylinux-i686-image") == "manylinux2014"
|
||||
|
||||
assert (
|
||||
options_reader.get("test-requires", list_sep=" ")
|
||||
options_reader.get("test-requires", option_format=ListFormat(" "))
|
||||
== {"windows": "docs", "macos": "docs", "linux": "scod"}[platform]
|
||||
)
|
||||
assert options_reader.get("test-command") == "mytest"
|
||||
@@ -174,7 +172,7 @@ repairs-wheel-command = "repair-project-linux"
|
||||
"""
|
||||
)
|
||||
|
||||
with pytest.raises(ConfigOptionError) as excinfo:
|
||||
with pytest.raises(OptionsReaderError) as excinfo:
|
||||
OptionsReader(pyproject_toml, platform="linux", env={})
|
||||
|
||||
assert "repair-wheel-command" in str(excinfo.value)
|
||||
@@ -191,7 +189,7 @@ repair_wheel_command = "repair-project-linux"
|
||||
"""
|
||||
)
|
||||
|
||||
with pytest.raises(ConfigOptionError) as excinfo:
|
||||
with pytest.raises(OptionsReaderError) as excinfo:
|
||||
OptionsReader(pyproject_toml, platform="linux", env={})
|
||||
|
||||
assert "repair-wheel-command" in str(excinfo.value)
|
||||
@@ -205,7 +203,7 @@ def test_unexpected_table(tmp_path):
|
||||
repair-wheel-command = "repair-project-linux"
|
||||
"""
|
||||
)
|
||||
with pytest.raises(ConfigOptionError):
|
||||
with pytest.raises(OptionsReaderError):
|
||||
OptionsReader(pyproject_toml, platform="linux", env={})
|
||||
|
||||
|
||||
@@ -219,8 +217,8 @@ build = ["1", "2"]
|
||||
)
|
||||
options_reader = OptionsReader(pyproject_toml, platform="linux", env={})
|
||||
|
||||
assert options_reader.get("build", list_sep=", ") == "1, 2"
|
||||
with pytest.raises(ConfigOptionError):
|
||||
assert options_reader.get("build", option_format=ListFormat(", ")) == "1, 2"
|
||||
with pytest.raises(OptionsReaderError):
|
||||
options_reader.get("build")
|
||||
|
||||
|
||||
@@ -234,7 +232,7 @@ manylinux-x86_64-image = "manylinux1"
|
||||
)
|
||||
disallow = {"windows": {"manylinux-x86_64-image"}}
|
||||
OptionsReader(pyproject_toml, platform="linux", disallow=disallow, env={})
|
||||
with pytest.raises(ConfigOptionError):
|
||||
with pytest.raises(OptionsReaderError):
|
||||
OptionsReader(pyproject_toml, platform="windows", disallow=disallow, env={})
|
||||
|
||||
|
||||
@@ -305,7 +303,7 @@ def test_resolve_cascade_merge_list(ignore_empty, rule):
|
||||
(["b1", "b2"], rule),
|
||||
(None, InheritRule.NONE),
|
||||
ignore_empty=ignore_empty,
|
||||
list_sep=" ",
|
||||
option_format=ListFormat(" "),
|
||||
)
|
||||
|
||||
if not ignore_empty:
|
||||
@@ -326,24 +324,34 @@ def test_resolve_cascade_merge_dict(rule):
|
||||
(None, InheritRule.NONE),
|
||||
({"value": "override"}, rule),
|
||||
(None, InheritRule.NONE),
|
||||
table_format={"item": "{k}={v}", "sep": " "},
|
||||
option_format=ShlexTableFormat(),
|
||||
)
|
||||
|
||||
if rule == InheritRule.PREPEND:
|
||||
assert answer == "value=override value=a1 base=b1"
|
||||
assert answer == "value=a1 base=b1"
|
||||
elif rule == InheritRule.NONE:
|
||||
assert answer == "value=override"
|
||||
elif rule == InheritRule.APPEND:
|
||||
assert answer == "value=a1 base=b1 value=override"
|
||||
assert answer == "value=override base=b1"
|
||||
|
||||
|
||||
def test_resolve_cascade_merge_strings():
|
||||
answer = _resolve_cascade(
|
||||
("value=a1 base=b1", InheritRule.NONE),
|
||||
("value=override", InheritRule.APPEND),
|
||||
option_format=ShlexTableFormat(),
|
||||
)
|
||||
assert answer == "value=override base=b1"
|
||||
|
||||
|
||||
def test_resolve_cascade_merge_different_types():
|
||||
answer = _resolve_cascade(
|
||||
({"value": "a1", "base": "b1"}, InheritRule.NONE),
|
||||
("value=a1 base=b1", InheritRule.NONE),
|
||||
({"value": "override"}, InheritRule.APPEND),
|
||||
table_format={"item": "{k}={v}", "sep": " "},
|
||||
("extra_string_var=c1", InheritRule.APPEND),
|
||||
option_format=ShlexTableFormat(),
|
||||
)
|
||||
assert answer == "value=a1 base=b1 value=override"
|
||||
assert answer == "value=override base=b1 extra_string_var=c1"
|
||||
|
||||
|
||||
PYPROJECT_2 = """
|
||||
@@ -387,28 +395,28 @@ def test_pyproject_2(tmp_path, platform):
|
||||
pyproject_toml.write_text(PYPROJECT_2)
|
||||
|
||||
options_reader = OptionsReader(config_file_path=pyproject_toml, platform=platform, env={})
|
||||
assert options_reader.get("test-command", list_sep=" && ") == "pyproject"
|
||||
assert options_reader.get("test-command", option_format=ListFormat(" && ")) == "pyproject"
|
||||
|
||||
with options_reader.identifier("random"):
|
||||
assert options_reader.get("test-command", list_sep=" && ") == "pyproject"
|
||||
assert options_reader.get("test-command", option_format=ListFormat(" && ")) == "pyproject"
|
||||
|
||||
with options_reader.identifier("cp37-something"):
|
||||
assert (
|
||||
options_reader.get("test-command", list_sep=" && ")
|
||||
options_reader.get("test-command", option_format=ListFormat(" && "))
|
||||
== "pyproject-override && override2 && pyproject"
|
||||
)
|
||||
assert (
|
||||
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
|
||||
options_reader.get("environment", option_format=EnvironmentFormat())
|
||||
== 'FOO="BAR" HAM="EGGS" FOO="BAZ" PYTHON="MONTY"'
|
||||
)
|
||||
|
||||
with options_reader.identifier("cp37-final"):
|
||||
assert (
|
||||
options_reader.get("test-command", list_sep=" && ")
|
||||
options_reader.get("test-command", option_format=ListFormat(" && "))
|
||||
== "extra-prepend && pyproject-override && override2 && pyproject && pyproject-finalize && finalize2 && extra-finalize"
|
||||
)
|
||||
assert (
|
||||
options_reader.get("environment", table_format={"item": '{k}="{v}"', "sep": " "})
|
||||
options_reader.get("environment", option_format=EnvironmentFormat())
|
||||
== 'FOO="BAR" HAM="EGGS" FOO="BAZ" PYTHON="MONTY"'
|
||||
)
|
||||
|
||||
@@ -426,7 +434,7 @@ test-command = "pyproject-override"
|
||||
"""
|
||||
)
|
||||
|
||||
with pytest.raises(ConfigOptionError):
|
||||
with pytest.raises(OptionsReaderError):
|
||||
OptionsReader(config_file_path=pyproject_toml, platform=platform, env={})
|
||||
|
||||
|
||||
@@ -442,8 +450,8 @@ other = ["two", "three"]
|
||||
|
||||
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
|
||||
assert (
|
||||
options_reader.get("config-settings", table_format={"item": '{k}="{v}"', "sep": " "})
|
||||
== 'example="one" other="two" other="three"'
|
||||
options_reader.get("config-settings", option_format=ShlexTableFormat(pair_sep="=", sep=" "))
|
||||
== "example=one other=two other=three"
|
||||
)
|
||||
|
||||
|
||||
@@ -458,10 +466,8 @@ def test_pip_config_settings(tmp_path):
|
||||
|
||||
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
|
||||
assert (
|
||||
options_reader.get(
|
||||
"config-settings", table_format={"item": "--config-settings='{k}=\"{v}\"'", "sep": " "}
|
||||
)
|
||||
== "--config-settings='--build-option=\"--use-mypyc\"'"
|
||||
options_reader.get("config-settings", option_format=ShlexTableFormat(sep=" ", pair_sep="="))
|
||||
== "--build-option=--use-mypyc"
|
||||
)
|
||||
|
||||
|
||||
@@ -471,12 +477,16 @@ def test_overrides_inherit(tmp_path):
|
||||
"""\
|
||||
[tool.cibuildwheel]
|
||||
before-all = ["before-all"]
|
||||
config-settings = {key1="value1", key2="value2", empty=""}
|
||||
|
||||
[[tool.cibuildwheel.overrides]]
|
||||
select = "cp37*"
|
||||
inherit.before-all = "append"
|
||||
before-all = ["override1"]
|
||||
|
||||
inherit.config-settings = "append"
|
||||
config-settings = {key3="value3", key2="override2"}
|
||||
|
||||
[[tool.cibuildwheel.overrides]]
|
||||
select = "cp37*"
|
||||
inherit.before-all = "prepend"
|
||||
@@ -486,9 +496,17 @@ before-all = ["override2"]
|
||||
|
||||
options_reader = OptionsReader(config_file_path=pyproject_toml, platform="linux", env={})
|
||||
with options_reader.identifier("cp38-something"):
|
||||
assert options_reader.get("before-all", list_sep=" && ") == "before-all"
|
||||
assert options_reader.get("before-all", option_format=ListFormat(" && ")) == "before-all"
|
||||
assert (
|
||||
options_reader.get("config-settings", option_format=ShlexTableFormat())
|
||||
== "key1=value1 key2=value2 empty=''"
|
||||
)
|
||||
with options_reader.identifier("cp37-something"):
|
||||
assert (
|
||||
options_reader.get("before-all", list_sep=" && ")
|
||||
options_reader.get("before-all", option_format=ListFormat(" && "))
|
||||
== "override2 && before-all && override1"
|
||||
)
|
||||
assert (
|
||||
options_reader.get("config-settings", option_format=ShlexTableFormat())
|
||||
== "key1=value1 key2=override2 empty='' key3=value3"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user