* Update dependencies
* restore graalpy windows workaround
* aand the other one
---------
Co-authored-by: cibuildwheel-bot[bot] <83877280+cibuildwheel-bot[bot]@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
Architecture name lookup in `parse_config` was a case-sensitive StrEnum
lookup. Since the enum carries both lowercase `arm64` (macOS/Android) and
uppercase `ARM64` (Windows), `parse_config("arm64", "windows")` silently
returned the macOS member and later failed with a confusing "Invalid archs
option" error, while lowercase `amd64` failed to parse at all.
Resolve names case-insensitively, preferring a member valid for the target
platform before falling back to any case-insensitive match (which keeps the
clear ConfigurationError for genuinely invalid names).
Closes#2373
Assisted-by: ClaudeCode:claude-opus-4.8
* chore: minor cleanups and perf tweaks from code review
- util/file.py, util/python_build_standalone.py: use hashlib.file_digest
for streaming SHA-256 verification instead of loading whole archives
into memory with read_bytes()
- logger.py: convert colors/symbols properties to functools.cached_property
so the Colors/Symbols objects are constructed only once per Logger instance
- platforms/windows.py: remove redundant .strip() on where_pip (already
stripped at assignment)
- util/python_build_standalone.py: remove unreachable python_base_dir.exists()
guard (callers always pass a fresh temp subdirectory)
- util/file.py: add comment explaining the getattr shim for
tar_.extraction_filter and when it can be removed
Assisted-by: ClaudeCode:claude-fable-5
* revert: restore assertion to check python_base_dir existence
* Add FAQ section on caching cibuildwheel's downloaded tools
Adds a Tips entry covering:
- What cibuildwheel caches (CPython/PyPy installers, virtualenv,
python-build-standalone archives) and the default per-OS cache folder.
- How to override the cache location with ``CIBW_CACHE_PATH``.
- A worked GitHub Actions example pairing ``actions/cache`` with
``CIBW_CACHE_PATH`` so the cache survives between runs.
- A pointer to ``--clean-cache`` for invalidating stale entries.
Closes#1585.
Per @joerick's request in the issue ("a caching section in the FAQ
would be great, if you can contribute it") the scope is intentionally
narrow — just FAQ-level guidance. Platform-specific caching (e.g.
Windows NuGet, addressed in #2839) lives in the platforms doc.
* docs: bump actions/cache v4 to v5
* docs: move cache to runner.temp, add cache poisoning warning (review feedback)
Drops the GraalPy 3.11 / GraalPy 24.2 builds (gp311_242) as agreed in
pypa/cibuildwheel#2741: a ~6-month overlap after the GraalPy 25 (gp312)
release. GraalPy 3.12 (gp312_250) stays.
This also removes the GraalPy 24-only workarounds that were explicitly
marked "Remove when GraalPy 24.x is dropped":
- the Visual Studio compiler-discovery (vswhere) and build-isolation
(graalpython#491) workarounds in the Windows backend
- the issue-491 Windows skip/filter hacks in test_pep518 and
test_dependency_versions (added in the original GraalPy PR #1538 and
unneeded since GraalPy 25 per #2597)
The uv-doesn't-support-graalpy skip (#2754), the `graalpy` enable group,
and the generated constraints pins apply to all GraalPy and are kept.
Assisted-by: ClaudeCode:claude-opus-4.8
* chore: use ConfigurationError when package_dir is outside cwd
Replace a generic Exception with errors. ConfigurationError when package_dir is not inside the working directory. This makes the error type consistent with the project's error handling and allows the CLI to treat this as a fatal error with the expected exit behavior.
* test: merge linux package_dir test into linux_build_steps_test
Fold the standalone linux_build_test.py into the existing
linux_build_steps_test.py, which already covers the linux platform
build orchestration. Reuses the file's existing import boilerplate and
module-qualified build() call style.
Assisted-by: ClaudeCode:claude-opus-4.8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Replace the explicit if/else used to resolve pinned container images with pinned_images.get(config_value, config_value) in the manylinux and musllinux loops inside _compute_build_options. This keeps behavior identical while reducing duplication and simplifying the code in cibuildwheel/options.py.
* ci: improve Azure test reliability
Azure has intermittent failures, often the macOS framework-Python
`posix_spawn: Undefined error: 0` spawn race under load, plus transient
download flakiness. Address both:
- Retry integration tests via pytest-rerunfailures (already required):
add `--reruns=2 --reruns-delay=5` to the serial and non-serial runs so a
single transient flake self-heals instead of failing the whole job.
- Cap Azure at `--num-processes 3` to reduce concurrent process spawning
(the macOS runner was using 4 xdist workers), lowering the spawn-race
probability and peak resource pressure.
- Cache downloads across runs: relocate CIBW_CACHE_PATH to a stable path
and add a Cache@2 task (interpreter downloads + per-worker test pip
caches live under it), cutting the network-download flake surface.
- Bump the Azure host interpreter to 3.13.
Assisted-by: ClaudeCode:claude-opus-4.8
* ci: stabilize iOS tests, bound rerun cost
An iOS run on Azure (build 9043) hung for the full 40-min pytest timeout
on the second build config of test_ios_platforms, then reran twice
(reruns=2), blowing past the 180-min job cap with no useful signal. The
hang was a stuck simulator/xcodebuild on the second config, after the
first config had run.
- Shut down running simulators before each parametrized config via a
`clean_ios_simulators` fixture, so a simulator left booted/wedged by the
previous config isn't reused.
- Drop iOS reruns from 2 to 1. One retry still covers the documented
"fails the first time" simulator-boot flake, while halving the
worst-case retry cost (3x40=120min -> 2x40=80min) on a hang.
Assisted-by: ClaudeCode:claude-opus-4.8
* ci: don't limit num processes
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* ci: rerun OCI unit tests that pull from Docker Hub
test_local_image et al. occasionally fail on a transient Docker Hub
anonymous-pull blip ("unauthorized: authentication required") when
pulling debian:trixie-slim. The integration runs already self-heal via
pytest-rerunfailures, but the unit run had no reruns, so a single flake
failed the whole job. Mark the three network-dependent OCI tests
(test_local_image, test_enter_error, test_multiarch_image) flaky so they
retry instead of blanket-rerunning the suite.
Assisted-by: ClaudeCode:claude-opus-4.8
* Drop iOS clean step
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
* ci: scope integration reruns to test_0_basic::test
Drop the blanket --reruns from the serial and non-serial integration
runs and instead mark test_0_basic.py::test as flaky, so only the known
flaky basic test is retried.
Assisted-by: ClaudeCode:claude-opus-4.8
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
`OCIContainer.__enter__` was hardened in #2879 to always clean up on
failure, but `__exit__` was left unguarded. If the container/bash had
already died, `bash_stdin.write("exit 0")` raises `BrokenPipeError`; if
bash refuses to exit, `process.wait(timeout=30)` raises `TimeoutExpired`.
Either propagated out of `__exit__` before `_remove_container()` ran,
leaking the container (and, on timeout, the `start` process too).
Wrap the teardown so a broken pipe or timeout instead forces the process
down (kill + wait) and always falls through to container removal, while
still respecting CIBW_DEBUG_KEEP_CONTAINER. Pipe closes are now also
guarded so a flush-on-close against a dead pipe can't mask cleanup.
Add non-docker unit tests for the clean-exit, already-dead-bash, and
shutdown-timeout paths.
Assisted-by: ClaudeCode:claude-opus-4.8
* fix: minor 4.0 issues in android validation, docs, and docstring
- android: raise a clear FatalError when ANDROID_API_LEVEL is not an
integer, instead of an uncaught ValueError deep in localized_vars
- docs: note that delvewheel is the default Windows repair-wheel-command
since 4.0 and how to skip it for platform-tagged wheels with no
extension module; update the now-outdated FAQ wording
- venv: fix _parse_pip_constraint_for_virtualenv docstring to say
marker-bearing constraints are evaluated against the host's default
environment (not skipped) when marker_env is None
Assisted-by: ClaudeCode:claude-opus-4.8
* fix: use int() with original error for ANDROID_API_LEVEL validation
Handle ANDROID_API_LEVEL validation via try/except around int() so the
original exception message is surfaced, and so non-ASCII Unicode digits
(which isdigit() accepts but int() may reject) are handled correctly.
Assisted-by: ClaudeCode:claude-opus-4.8
* refactor: address reivew by moving error catch
Assisted-by: ClaudeCode:claude-opus-4.8
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: detect musl libc when downloading python-build-standalone
`platform.libc_ver()` only ever reports glibc and returns `("", "")` on
musl systems, so `"musl" in platform.libc_ver()` was never true and musl
hosts (e.g. Alpine) always selected the `gnu` python-build-standalone
asset, which won't run.
Detect musl by shelling out to `ldd --version`, which prints "musl libc"
on musl-based systems. This probes the actual system loader rather than
the host Python's linkage, so it stays correct even when cibuildwheel
runs under a relocatable/statically-linked interpreter. Falls back to
glibc when `ldd` is unavailable.
Assisted-by: ClaudeCode:claude-opus-4.8
* test: add type annotations to satisfy mypy and ruff
Assisted-by: ClaudeCode:claude-opus-4.8
The linux32 sanity check added in #2880 omitted `*platform_args`, unlike
the surrounding `uname -m` probes and the `create` command. On the i386
fallback path `platform_args` is reassigned to AMD64, so without
forwarding it the check could run against a different image variant than
the one actually built (e.g. on a multi-platform/containerd backend),
making the check meaningless or pulling the wrong variant.
Assisted-by: ClaudeCode:claude-opus-4.8
* Try to fix the problem with py trying to execute the shebang
* run whenever the branch name starts with gitlab
* Modernise GitLab CI config
- Windows: remove stale servercore:1809 image and choco install
(runners are now Windows 2022 VMs with Python 3.13 pre-installed)
- macOS: update deprecated macos-14-xcode-15 to macos-15-xcode-16
- Linux: bump Python image from 3.12 to 3.13
- All jobs: also run on gitlab* branches with CIBW_ENABLE=all
Generated with the help of AI (Amp/Claude Opus 4.7)
Amp-Thread-ID: https://ampcode.com/threads/T-019e6496-f89a-74e7-9f6b-655574290e68
Co-authored-by: Amp <amp@ampcode.com>
* ci: exclude graalpy on GitLab Windows runners
GraalPy is JVM-based and slow to start; on the small (2-core) GitLab
SaaS Windows runners, virtualenv's interpreter query for graalpy.exe
times out, failing test_0_basic::test[pip]. Restrict the Windows job's
CIBW_ENABLE to all groups except graalpy (other platforms keep "all").
CIBW_ENABLE rather than CIBW_SKIP is used so the test's expected-wheel
set (derived from CIBW_ENABLE) stays consistent with what is built.
Assisted-by: ClaudeCode:claude-opus-4.8
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Henry Schreiner <henryfs@princeton.edu>
This was the case when running `nox -s tests -- --run-podman -v -s 'unit_test/oci_container_test.py::test_multiarch_image[podman-OCIPlatform.i386]'` on macOS arm64.
* fix: ensure clean-up on container start failure and warn on removal failure
Properly release resources on container start failure.
If we fail to remove the created container, warn when not running in CI.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* chore: add unit tests for `OCIContainer._get_platform_args`
While this was already tested indirectly through `test_local_image`, this makes the behaviour check of `OCIContainer._get_platform_args` clear.
* fix: re-add `check=False` removed at some point in local testing