diff --git a/.cirrus.yml b/.cirrus.yml
index 7385d88a..e85ef479 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -6,6 +6,7 @@ run_tests: &RUN_TESTS
linux_x86_task:
+ timeout_in: 120m
compute_engine_instance:
image_project: cirrus-images
image: family/docker-builder
@@ -33,7 +34,7 @@ linux_aarch64_task:
windows_x86_task:
# The task takes ~55 minutes while the timeout happens
# after 60 minutes by default, let's allow some wiggle room.
- timeout_in: 90m
+ timeout_in: 120m
windows_container:
image: cirrusci/windowsservercore:visualstudio2022
cpu: 8
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 75f15052..deccf5dc 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
- id: trailing-whitespace
- repo: https://github.com/asottile/pyupgrade
- rev: v2.37.3
+ rev: v2.38.0
hooks:
- id: pyupgrade
args: ["--py37-plus"]
diff --git a/README.md b/README.md
index af5dbf5f..bfb40a63 100644
--- a/README.md
+++ b/README.md
@@ -55,10 +55,10 @@ Usage
|-----------------|-------|-------|---------|-----------|-----------|
| GitHub Actions | ✅ | ✅ | ✅ | ✅¹ | ✅² |
| Azure Pipelines | ✅ | ✅ | ✅ | | ✅² |
-| Travis CI | ✅ | | ✅ | ✅ | ✅² |
+| Travis CI | ✅ | | ✅ | ✅ | |
| AppVeyor | ✅ | ✅ | ✅ | | ✅² |
| CircleCI | ✅ | ✅ | | | ✅² |
-| Gitlab CI | ✅ | | | | ✅² |
+| Gitlab CI | ✅ | | | | |
| Cirrus CI | ✅ | ✅³ | ✅ | ✅ | ✅ |
¹ [Requires emulation](https://cibuildwheel.readthedocs.io/en/stable/faq/#emulation), distributed separately. Other services may also support Linux ARM through emulation or third-party build hosts, but these are not tested in our CI.
@@ -92,7 +92,7 @@ jobs:
- uses: actions/setup-python@v3
- name: Install cibuildwheel
- run: python -m pip install cibuildwheel==2.9.0
+ run: python -m pip install cibuildwheel==2.10.2
- name: Build wheels
run: python -m cibuildwheel --output-dir wheelhouse
@@ -208,6 +208,32 @@ Changelog
+### v2.10.2
+
+_25 September 2022_
+
+- 🐛 Fix a bug that caused `win32` identifiers to fail when used with `--only`. (#1282)
+- 🐛 Fix computation of `auto`/`auto64`/`auto32` archs when targeting a different platform to the one that you're running cibuildwheel on. (#1266)
+- 📚 Fix an mistake in the 'how it works' diagram. (#1274)
+
+### v2.10.1
+
+_18 September 2022_
+
+- 🐛 Fix a bug that stopped environment variables specified in TOML from being expanded. (#1273)
+
+### v2.10.0
+
+_13 September 2022_
+
+- 🌟 Adds support for [building wheels on Cirrus CI](https://cibuildwheel.readthedocs.io/en/stable/setup/#cirrus-ci). This is exciting for us, as it's the first public CI platform that natively supports macOS Apple Silicon (aka. M1, `arm64`) runners. As such, it's the first platform that you can natively build _and test_ macOS `arm64` wheels. It also has native Linux ARM (aarch64) runners, for fast, native builds there. (#1191)
+- 🌟 Adds support for running cibuildwheel on Apple Silicon machines. For a while, we've supported cross-compilation of Apple Silicon wheels on `x86_64`, but now that we have Cirrus CI we can run our test suite and officially support running cibuildwheel on `arm64`. (#1191)
+- ✨ Adds the `--only` [command line option](https://cibuildwheel.readthedocs.io/en/stable/options/#command-line), to specify a single build to run. Previously, it could be cumbersome to set all the build selection options to target a specific build - for example, you might have to run something like `CIBW_BUILD=cp39-manylinux_x86_64 cibuildwheel --platform linux --archs x86_64`. The new `--only` option overrides all the build selection options to simplify running a single build, which now looks like `cibuildwheel --only cp39-manylinux_x86_64`. (#1098)
+- ✨ Adds the [`CIBW_CONFIG_SETTINGS`](https://cibuildwheel.readthedocs.io/en/stable/options/#config-settings) option, so you can pass arguments to your package's build backend (#1244)
+- 🛠 Updates the CPython 3.11 version to the latest release candidate - v3.11.0rc2. (#1265)
+- 🐛 Fix a bug that can cause a RecursionError on Windows when building from an sdist. (#1253)
+- 🛠 Add support for the s390x architecture on manylinux_2_28 (#1255)
+
### v2.9.0
_11 August 2022_
@@ -226,34 +252,6 @@ _18 July 2022_
- 🛠 The GitHub Action will ensure a compatible version of Python is installed on the runner (#1114)
- 📚 A few docs improvements
-### v2.8.0
-
-_5 July 2022_
-
-- ✨ You can now run cibuildwheel on Podman, as an alternate container engine to Docker (which remains the default). This is useful in environments where a Docker daemon isn't available, for example, it can be run inside a Docker container, or without root access. To use Podman, set the [`CIBW_CONTAINER_ENGINE`](https://cibuildwheel.readthedocs.io/en/stable/options/#container-engine) option. (#966)
-- ✨ Adds support for building `py3-none-{platform}` wheels. This works the same as ABI3 - wheels won't be rebuilt, but tests will still be run across all selected versions of Python.
-
- > These wheels contain native extension code, but don't use the Python APIs. Typically, they're bridged to Python using a FFI module like [ctypes](https://docs.python.org/3/library/ctypes.html) or [cffi](https://cffi.readthedocs.io/en/latest/). Because they don't use Python ABI, the wheels are more compatible - they work across many Python versions.
-
- Check out this [example ctypes project](https://github.com/joerick/python-ctypes-package-sample) to see an example of how it works. (#1151)
-- 🛠 cibuildwheel will now error if multiple builds in a single run produce the same wheel filename, as this indicates a misconfiguration. (#1152)
-- 📚 A few docs improvements and updates to keep things up-to-date.
-
-### v2.7.0
-
-_17 June 2022_
-
-- 🌟 Added support for the new `manylinux_2_28` images. These new images are based on AlmaLinux, the community-driven successor to CentOS, unlike manylinux_2_24, which was based on Debian. To build on these images, set your [`CIBW_MANYLINUX_*_IMAGE`](https://cibuildwheel.readthedocs.io/en/stable/options/#linux-image) option to `manylinux_2_28`. (#1026)
-- 🐛 Fix a bug where tests were not being run on CPython 3.11 (when CIBW_PRERELEASE_PYTHONS was set) (#1138)
-- ✨ You can now build Linux wheels on Windows, as long as you have Docker installed and set to 'Linux containers' (#1117)
-- 🐛 Fix a bug on macOS that caused cibuildwheel to crash trying to overwrite a previously-built wheel of the same name. (#1129)
-
-### v2.6.1
-
-_7 June 2022_
-
-- 🛠 Update the prerelease CPython 3.11 to 3.11.0b3
-
---
diff --git a/action.yml b/action.yml
index a27269dd..111acc93 100644
--- a/action.yml
+++ b/action.yml
@@ -13,6 +13,10 @@ inputs:
description: 'File containing the config, defaults to {package}/pyproject.toml'
required: false
default: ''
+ only:
+ description: 'Build a specific wheel only. No need for arch/platform if this is set'
+ required: false
+ default: ''
branding:
icon: package
color: yellow
@@ -36,5 +40,6 @@ runs:
${{ inputs.package-dir }}
--output-dir ${{ inputs.output-dir }}
--config-file "${{ inputs.config-file }}"
+ --only "${{ inputs.only }}"
2>&1
shell: bash
diff --git a/bin/inspect_all_known_projects.py b/bin/inspect_all_known_projects.py
index 542e42b8..3f91b2b5 100755
--- a/bin/inspect_all_known_projects.py
+++ b/bin/inspect_all_known_projects.py
@@ -1,4 +1,17 @@
#!/usr/bin/env python3
+
+"""
+Check known projects for usage of requires-python.
+
+Usage:
+
+ ./bin/inspect_all_known_projects.py --online=$GITHUB_TOKEN
+
+This will cache the results to all_known_setup.yaml; you can reprint
+the results without the `--online` setting.
+"""
+
+
from __future__ import annotations
import ast
@@ -7,7 +20,7 @@ from typing import Iterator
import click
import yaml
-from ghapi.core import GhApi, HTTP404NotFoundError
+from github import Github, GithubException
from rich import print
from cibuildwheel.projectfiles import Analyzer
@@ -47,33 +60,38 @@ def check_repo(name: str, contents: str) -> str:
class MaybeRemote:
- def __init__(self, cached_file: Path | str, *, online: bool) -> None:
- self.online = online
- if self.online:
- self.contents: dict[str, dict[str, str | None]] = {
+ github: Github | None
+ contents: dict[str, dict[str, str | None]]
+
+ def __init__(self, cached_file: Path | str, *, online: str | None) -> None:
+ if online is not None:
+ self.github = Github(online)
+ self.contents = {
"setup.py": {},
"setup.cfg": {},
"pyproject.toml": {},
}
else:
+ self.github = None
with open(cached_file) as f:
self.contents = yaml.safe_load(f)
def get(self, repo: str, filename: str) -> str | None:
- if self.online:
+ if self.github:
try:
- self.contents[filename][repo] = (
- GhApi(*repo.split("/")).get_content(filename).decode()
- )
- except HTTP404NotFoundError:
+ gh_file = self.github.get_repo(repo).get_contents(filename)
+ except GithubException:
self.contents[filename][repo] = None
+ else:
+ assert not isinstance(gh_file, list)
+ self.contents[filename][repo] = gh_file.decoded_content.decode(encoding="utf-8")
+
return self.contents[filename][repo]
elif repo in self.contents[filename]:
return self.contents[filename][repo]
else:
- raise RuntimeError(
- f"Trying to access {repo}:{filename} and not in cache, rebuild cache"
- )
+ msg = f"Trying to access {repo}:{filename} and not in cache, rebuild cache"
+ raise RuntimeError(msg)
def save(self, filename: Path | str) -> None:
with open(filename, "w") as f:
@@ -87,8 +105,8 @@ class MaybeRemote:
@click.command()
-@click.option("--online", is_flag=True, help="Remember to set GITHUB_TOKEN")
-def main(online: bool) -> None:
+@click.option("--online", help="Set to $GITHUB_TOKEN")
+def main(online: str | None) -> None:
with open(DIR / "../docs/data/projects.yml") as f:
known = yaml.safe_load(f)
diff --git a/bin/run_example_ci_configs.py b/bin/run_example_ci_configs.py
index b96dfd2d..9cd28daa 100755
--- a/bin/run_example_ci_configs.py
+++ b/bin/run_example_ci_configs.py
@@ -81,7 +81,8 @@ def ci_service_for_config_file(config_file):
if service.name == service_name:
return service
- raise ValueError(f"unknown ci service for config file {config_file}")
+ msg = f"unknown ci service for config file {config_file}"
+ raise ValueError(msg)
@click.command()
@@ -100,7 +101,8 @@ def run_example_ci_configs(config_files=None):
for config_file in config_files:
service = ci_service_for_config_file(config_file)
if service.name in configs_by_service:
- raise Exception("You cannot specify more than one config per CI service")
+ msg = "You cannot specify more than one config per CI service"
+ raise Exception(msg)
configs_by_service[service.name] = config_file
if git_repo_has_changes():
diff --git a/bin/update_how_it_works_image.py b/bin/update_how_it_works_image.py
new file mode 100644
index 00000000..b7b433fb
--- /dev/null
+++ b/bin/update_how_it_works_image.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+
+from __future__ import annotations
+
+import subprocess
+import sys
+from pathlib import Path
+
+try:
+ from html2image import Html2Image # type: ignore[import]
+except ImportError:
+ sys.exit(
+ """
+ html2image not found. Ensure you have Chrome (on Mac/Windows) or
+ Chromium (on Linux) installed, and then do:
+ pip install html2image
+ """
+ )
+
+
+def main():
+ subprocess.run(["mkdocs", "build"])
+
+ hti = Html2Image(custom_flags=["--force-device-scale-factor=2"])
+
+ html_str = Path("docs/diagram.md").read_text()
+ css_tags = f"""
+
+
+
+
+ """
+ html_str = css_tags + html_str
+
+ [screenshot, *_] = hti.screenshot(
+ html_str=html_str,
+ size=(830, 405),
+ )
+
+ dest_path = Path("docs/data/how-it-works.png")
+ if dest_path.exists():
+ dest_path.unlink()
+
+ Path(screenshot).rename(dest_path)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/bin/update_pythons.py b/bin/update_pythons.py
index 6dac0b76..0227c361 100755
--- a/bin/update_pythons.py
+++ b/bin/update_pythons.py
@@ -141,7 +141,8 @@ class PyPyVersions:
releases = [r for r in releases if self.get_arch_file(r)]
if not releases:
- raise RuntimeError(f"PyPy Win {self.arch} not found for {spec}! {self.releases}")
+ msg = f"PyPy Win {self.arch} not found for {spec}! {self.releases}"
+ raise RuntimeError(msg)
version_arch = "win32" if self.arch == "32" else "win_amd64"
@@ -159,13 +160,15 @@ class PyPyVersions:
def update_version_macos(self, spec: Specifier) -> ConfigMacOS:
if self.arch != "64":
- raise RuntimeError("Other archs not supported yet on macOS")
+ msg = "Other archs not supported yet on macOS"
+ raise RuntimeError(msg)
releases = [r for r in self.releases if spec.contains(r["python_version"])]
releases = sorted(releases, key=lambda r: r["pypy_version"]) # type: ignore[no-any-return]
if not releases:
- raise RuntimeError(f"PyPy macOS {self.arch} not found for {spec}!")
+ msg = f"PyPy macOS {self.arch} not found for {spec}!"
+ raise RuntimeError(msg)
release = releases[-1]
version = release["python_version"]
diff --git a/cibuildwheel/__init__.py b/cibuildwheel/__init__.py
index a4f6f370..cc406c56 100644
--- a/cibuildwheel/__init__.py
+++ b/cibuildwheel/__init__.py
@@ -1,3 +1,3 @@
from __future__ import annotations
-__version__ = "2.9.0"
+__version__ = "2.10.2"
diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py
index f3b44261..1a9f296f 100644
--- a/cibuildwheel/__main__.py
+++ b/cibuildwheel/__main__.py
@@ -6,6 +6,7 @@ import shutil
import sys
import tarfile
import textwrap
+import typing
from pathlib import Path
from tempfile import mkdtemp
@@ -40,7 +41,7 @@ def main() -> None:
parser.add_argument(
"--platform",
choices=["auto", "linux", "macos", "windows"],
- default=os.environ.get("CIBW_PLATFORM", "auto"),
+ default=None,
help="""
Platform to build for. Use this option to override the
auto-detected platform or to run cibuildwheel on your development
@@ -64,6 +65,16 @@ def main() -> None:
""",
)
+ parser.add_argument(
+ "--only",
+ default=None,
+ help="""
+ Force a single wheel build when given an identifier. Overrides
+ CIBW_BUILD/CIBW_SKIP. --platform and --arch cannot be specified
+ if this is given.
+ """,
+ )
+
parser.add_argument(
"--output-dir",
type=Path,
@@ -138,7 +149,8 @@ def main() -> None:
try:
(project_dir,) = temp_dir.iterdir()
except ValueError:
- raise SystemExit("invalid sdist: didn't contain a single dir") from None
+ msg = "invalid sdist: didn't contain a single dir"
+ raise SystemExit(msg) from None
# This is now the new package dir
args.package_dir = project_dir.resolve()
@@ -154,10 +166,40 @@ def main() -> None:
def build_in_directory(args: CommandLineArguments) -> None:
+ platform_option_value = args.platform or os.environ.get("CIBW_PLATFORM", "auto")
platform: PlatformName
- if args.platform != "auto":
- platform = args.platform
+ if args.only:
+ if "linux_" in args.only:
+ platform = "linux"
+ elif "macosx_" in args.only:
+ platform = "macos"
+ elif "win_" in args.only or "win32" in args.only:
+ platform = "windows"
+ else:
+ print(
+ f"Invalid --only='{args.only}', must be a build selector with a known platform",
+ file=sys.stderr,
+ )
+ sys.exit(2)
+ if args.platform is not None:
+ print(
+ "--platform cannot be specified with --only, it is computed from --only",
+ file=sys.stderr,
+ )
+ sys.exit(2)
+ if args.archs is not None:
+ print(
+ "--arch cannot be specified with --only, it is computed from --only",
+ file=sys.stderr,
+ )
+ sys.exit(2)
+ elif platform_option_value != "auto":
+ if platform_option_value not in PLATFORMS:
+ print(f"cibuildwheel: Unsupported platform: {platform_option_value}", file=sys.stderr)
+ sys.exit(2)
+
+ platform = typing.cast(PlatformName, platform_option_value)
else:
ci_provider = detect_ci_provider()
if ci_provider is None:
@@ -187,10 +229,6 @@ def build_in_directory(args: CommandLineArguments) -> None:
)
sys.exit(2)
- if platform not in PLATFORMS:
- print(f"cibuildwheel: Unsupported platform: {platform}", file=sys.stderr)
- sys.exit(2)
-
options = compute_options(platform=platform, command_line_arguments=args)
package_dir = options.globals.package_dir
diff --git a/cibuildwheel/architecture.py b/cibuildwheel/architecture.py
index 7b90ff94..a922f6f5 100644
--- a/cibuildwheel/architecture.py
+++ b/cibuildwheel/architecture.py
@@ -3,12 +3,19 @@ from __future__ import annotations
import functools
import platform as platform_module
import re
+import sys
from enum import Enum
from .typing import Final, Literal, PlatformName, assert_never
PRETTY_NAMES: Final = {"linux": "Linux", "macos": "macOS", "windows": "Windows"}
+ARCH_SYNONYMS: Final[list[dict[PlatformName, str | None]]] = [
+ {"linux": "x86_64", "macos": "x86_64", "windows": "AMD64"},
+ {"linux": "i686", "macos": None, "windows": "x86"},
+ {"linux": "aarch64", "macos": "arm64", "windows": "ARM64"},
+]
+
@functools.total_ordering
class Architecture(Enum):
@@ -56,14 +63,37 @@ class Architecture(Enum):
@staticmethod
def auto_archs(platform: PlatformName) -> set[Architecture]:
- native_architecture = Architecture(platform_module.machine())
+ native_machine = platform_module.machine()
+
+ # Cross-platform support. Used for --print-build-identifiers or docker builds.
+ host_platform: PlatformName = (
+ "windows"
+ if sys.platform.startswith("win")
+ else ("macos" if sys.platform.startswith("darwin") else "linux")
+ )
+
+ native_architecture = Architecture(native_machine)
+
+ # we might need to rename the native arch to the machine we're running
+ # on, as the same arch can have different names on different platforms
+ if host_platform != platform:
+ for arch_synonym in ARCH_SYNONYMS:
+ if native_machine == arch_synonym.get(host_platform):
+ synonym = arch_synonym[platform]
+
+ if synonym is None:
+ # can't build anything on this platform
+ return set()
+
+ native_architecture = Architecture(synonym)
+
result = {native_architecture}
- if platform == "linux" and native_architecture == Architecture.x86_64:
+ if platform == "linux" and Architecture.x86_64 in result:
# x86_64 machines can run i686 containers
result.add(Architecture.i686)
- if platform == "windows" and native_architecture == Architecture.AMD64:
+ if platform == "windows" and Architecture.AMD64 in result:
result.add(Architecture.x86)
return result
diff --git a/cibuildwheel/bashlex_eval.py b/cibuildwheel/bashlex_eval.py
index 47e4aea3..01093a62 100644
--- a/cibuildwheel/bashlex_eval.py
+++ b/cibuildwheel/bashlex_eval.py
@@ -32,7 +32,8 @@ def evaluate(
command_node = bashlex.parsesingle(value)
if len(command_node.parts) != 1:
- raise ValueError(f'"{value}" has too many parts')
+ msg = f"{value!r} has too many parts"
+ raise ValueError(msg)
value_word_node = command_node.parts[0]
@@ -54,7 +55,8 @@ def evaluate_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
elif node.kind == "parameter":
return evaluate_parameter_node(node, context=context)
else:
- raise ValueError(f'Unsupported bash construct: "{node.kind}"')
+ msg = f"Unsupported bash construct: {node.kind!r}"
+ raise ValueError(msg)
def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) -> str:
@@ -65,10 +67,8 @@ def evaluate_word_node(node: bashlex.ast.node, context: NodeExecutionContext) ->
part_value = evaluate_node(part, context=context)
if part_string not in value:
- raise RuntimeError(
- f'bash parse failed. part "{part_string}" not found in "{value}". '
- f'Word was "{node.word}". Full input was "{context.input}"'
- )
+ msg = f"bash parse failed. part {part_string!r} not found in {value!r}. Word was {node.word!r}. Full input was {context.input!r}"
+ raise RuntimeError(msg)
value = value.replace(part_string, part_value, 1)
@@ -95,9 +95,11 @@ def evaluate_nodes_as_compound_command(
result += evaluate_command_node(node, context=context)
elif node.kind == "operator":
if node.op != ";":
- raise ValueError(f'Unsupported bash operator: "{node.op}"')
+ msg = f"Unsupported bash operator: {node.op!r}"
+ raise ValueError(msg)
else:
- raise ValueError(f'Unsupported bash node in compound command: "{node.kind}"')
+ msg = f"Unsupported bash node in compound command: {node.kind!r}"
+ raise ValueError(msg)
return result
diff --git a/cibuildwheel/environment.py b/cibuildwheel/environment.py
index a544852a..23ea9877 100644
--- a/cibuildwheel/environment.py
+++ b/cibuildwheel/environment.py
@@ -4,6 +4,7 @@ import dataclasses
from typing import Any, Mapping, Sequence
import bashlex
+import bashlex.errors
from cibuildwheel.typing import Protocol
@@ -33,7 +34,11 @@ def split_env_items(env_string: str) -> list[str]:
if not env_string:
return []
- command_node = bashlex.parsesingle(env_string)
+ try:
+ command_node = bashlex.parsesingle(env_string)
+ except bashlex.errors.ParsingError as e:
+ raise EnvironmentParseError(env_string) from e
+
result = []
for word_node in command_node.parts:
diff --git a/cibuildwheel/functools_cached_property_38.py b/cibuildwheel/functools_cached_property_38.py
index cbe4537a..879cdb62 100644
--- a/cibuildwheel/functools_cached_property_38.py
+++ b/cibuildwheel/functools_cached_property_38.py
@@ -21,10 +21,8 @@ class cached_property(Generic[_T]):
if self.attrname is None:
self.attrname = name
elif name != self.attrname:
- raise TypeError(
- "Cannot assign the same cached_property to two different names "
- f"({self.attrname!r} and {name!r})."
- )
+ msg = f"Cannot assign the same cached_property to two different names ({self.attrname!r} and {name!r})."
+ raise TypeError(msg)
@overload
def __get__(self, instance: None, owner: type[Any] | None = ...) -> cached_property[_T]:
@@ -38,9 +36,8 @@ class cached_property(Generic[_T]):
if instance is None:
return self
if self.attrname is None:
- raise TypeError(
- "Cannot use cached_property instance without calling __set_name__ on it."
- )
+ msg = "Cannot use cached_property instance without calling __set_name__ on it."
+ raise TypeError(msg)
try:
cache = instance.__dict__
except AttributeError: # not all objects have __dict__ (e.g. class defines slots)
diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py
index 5720074d..a64c829e 100644
--- a/cibuildwheel/linux.py
+++ b/cibuildwheel/linux.py
@@ -367,7 +367,8 @@ def build(options: Options, tmp_path: Path) -> None: # pylint: disable=unused-a
cwd = Path.cwd()
abs_package_dir = options.globals.package_dir.resolve()
if cwd != abs_package_dir and cwd not in abs_package_dir.parents:
- raise Exception("package_dir must be inside the working directory")
+ msg = "package_dir must be inside the working directory"
+ raise Exception(msg)
container_project_path = PurePosixPath("/project")
container_package_dir = container_project_path / abs_package_dir.relative_to(cwd)
diff --git a/cibuildwheel/logger.py b/cibuildwheel/logger.py
index 04d80413..70f22997 100644
--- a/cibuildwheel/logger.py
+++ b/cibuildwheel/logger.py
@@ -204,14 +204,16 @@ def build_description_from_identifier(identifier: str) -> str:
elif python_interpreter == "pp":
build_description += "PyPy"
else:
- raise Exception("unknown python")
+ msg = f"unknown python {python_interpreter!r}"
+ raise Exception(msg)
build_description += f" {python_version[0]}.{python_version[1:]} "
try:
build_description += PLATFORM_IDENTIFIER_DESCRIPTIONS[platform_identifier]
except KeyError as e:
- raise Exception("unknown platform") from e
+ msg = f"unknown platform {platform_identifier!r}"
+ raise Exception(msg) from e
return build_description
diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py
index f15a04f8..db863504 100644
--- a/cibuildwheel/macos.py
+++ b/cibuildwheel/macos.py
@@ -146,7 +146,8 @@ def setup_python(
elif implementation_id.startswith("pp"):
base_python = install_pypy(tmp, python_configuration.url)
else:
- raise ValueError("Unknown Python implementation")
+ msg = "Unknown Python implementation"
+ raise ValueError(msg)
assert base_python.exists()
log.step("Setting up build environment...")
@@ -466,7 +467,8 @@ def build(options: Options, tmp_path: Path) -> None:
)
)
else:
- raise RuntimeError("unreachable")
+ msg = "unreachable"
+ raise RuntimeError(msg)
# skip this test
continue
diff --git a/cibuildwheel/oci_container.py b/cibuildwheel/oci_container.py
index 91714c7e..c0c0cc9d 100644
--- a/cibuildwheel/oci_container.py
+++ b/cibuildwheel/oci_container.py
@@ -58,7 +58,8 @@ class OCIContainer:
engine: ContainerEngine = "docker",
):
if not image:
- raise ValueError("Must have a non-empty image to run.")
+ msg = "Must have a non-empty image to run."
+ raise ValueError(msg)
self.image = image
self.simulate_32_bit = simulate_32_bit
diff --git a/cibuildwheel/options.py b/cibuildwheel/options.py
index 241f0e0e..cb681fa3 100644
--- a/cibuildwheel/options.py
+++ b/cibuildwheel/options.py
@@ -10,7 +10,7 @@ from configparser import ConfigParser
from contextlib import contextmanager
from dataclasses import asdict, dataclass
from pathlib import Path
-from typing import Any, Dict, Generator, Iterator, List, Mapping, Union, cast
+from typing import Any, Callable, Dict, Generator, Iterator, List, Mapping, Union, cast
if sys.version_info >= (3, 11):
import tomllib
@@ -23,7 +23,7 @@ from .architecture import Architecture
from .environment import EnvironmentParseError, ParsedEnvironment, parse_environment
from .oci_container import ContainerEngine
from .projectfiles import get_requires_python_str
-from .typing import PLATFORMS, Literal, PlatformName, TypedDict
+from .typing import PLATFORMS, Literal, NotRequired, PlatformName, TypedDict
from .util import (
MANYLINUX_ARCHS,
MUSLLINUX_ARCHS,
@@ -42,9 +42,10 @@ from .util import (
@dataclass
class CommandLineArguments:
- platform: Literal["auto", "linux", "macos", "windows"]
+ platform: Literal["auto", "linux", "macos", "windows"] | None
archs: str | None
output_dir: Path
+ only: str | None
config_file: str
package_dir: Path
print_build_identifiers: bool
@@ -122,6 +123,7 @@ DISALLOWED_OPTIONS = {
class TableFmt(TypedDict):
item: str
sep: str
+ quote: NotRequired[Callable[[str], str]]
class ConfigOptionError(KeyError):
@@ -136,7 +138,8 @@ def _dig_first(*pairs: tuple[Mapping[str, Setting], str], ignore_empty: bool = F
_dig_first((dict1, "key1"), (dict2, "key2"), ...)
"""
if not pairs:
- raise ValueError("pairs cannot be empty")
+ msg = "pairs cannot be empty"
+ raise ValueError(msg)
for dict_like, key in pairs:
if key in dict_like:
@@ -206,13 +209,15 @@ class OptionsReader:
if config_overrides is not None:
if not isinstance(config_overrides, list):
- raise ConfigOptionError("'tool.cibuildwheel.overrides' must be a list")
+ msg = "'tool.cibuildwheel.overrides' must be a list"
+ raise ConfigOptionError(msg)
for config_override in config_overrides:
select = config_override.pop("select", None)
if not select:
- raise ConfigOptionError("'select' must be set in an override")
+ msg = "'select' must be set in an override"
+ raise ConfigOptionError(msg)
if isinstance(select, list):
select = " ".join(select)
@@ -326,14 +331,16 @@ class OptionsReader:
if isinstance(result, dict):
if table is None:
- raise ConfigOptionError(f"{name!r} does not accept a table")
+ msg = f"{name!r} does not accept a table"
+ raise ConfigOptionError(msg)
return table["sep"].join(
- item for k, v in result.items() for item in _inner_fmt(k, v, table["item"])
+ item for k, v in result.items() for item in _inner_fmt(k, v, table)
)
if isinstance(result, list):
if sep is None:
- raise ConfigOptionError(f"{name!r} does not accept a list")
+ msg = f"{name!r} does not accept a list"
+ raise ConfigOptionError(msg)
return sep.join(result)
if isinstance(result, int):
@@ -342,14 +349,16 @@ class OptionsReader:
return result
-def _inner_fmt(k: str, v: Any, table_item: str) -> Iterator[str]:
+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 = shlex.quote(inner_v)
- yield table_item.format(k=k, v=qv)
+ qv = quote_function(inner_v)
+ yield table["item"].format(k=k, v=qv)
else:
- qv = shlex.quote(v)
- yield table_item.format(k=k, v=qv)
+ qv = quote_function(v)
+ yield table["item"].format(k=k, v=qv)
class Options:
@@ -403,6 +412,15 @@ 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", sep=" ")
+ architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
+
+ # Process `--only`
+ if args.only:
+ build_config = args.only
+ skip_config = ""
+ architectures = Architecture.all_archs(self.platform)
+
build_selector = BuildSelector(
build_config=build_config,
skip_config=skip_config,
@@ -411,9 +429,6 @@ class Options:
)
test_selector = TestSelector(skip_config=test_skip)
- archs_config_str = args.archs or self.reader.get("archs", sep=" ")
- architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
-
container_engine_str = self.reader.get("container-engine")
if container_engine_str not in ["docker", "podman"]:
@@ -442,13 +457,13 @@ class Options:
build_frontend_str = self.reader.get("build-frontend", env_plat=False)
environment_config = self.reader.get(
- "environment", table={"item": "{k}={v}", "sep": " "}
+ "environment", table={"item": '{k}="{v}"', "sep": " "}
)
environment_pass = self.reader.get("environment-pass", sep=" ").split()
before_build = self.reader.get("before-build", sep=" && ")
repair_command = self.reader.get("repair-wheel-command", sep=" && ")
config_settings = self.reader.get(
- "config-settings", table={"item": "{k}={v}", "sep": " "}
+ "config-settings", table={"item": "{k}={v}", "sep": " ", "quote": shlex.quote}
)
dependency_versions = self.reader.get("dependency-versions")
@@ -588,6 +603,9 @@ class Options:
]
build_option_defaults = self.build_options(identifier=None)
+ build_options_for_identifier = {
+ identifier: self.build_options(identifier) for identifier in identifiers
+ }
for option_name, default_value in sorted(asdict(build_option_defaults).items()):
if option_name == "globals":
@@ -597,7 +615,7 @@ class Options:
# if any identifiers have an overridden value, print that too
for identifier in identifiers:
- option_value = getattr(self.build_options(identifier=identifier), option_name)
+ option_value = getattr(build_options_for_identifier[identifier], option_name)
if option_value != default_value:
lines.append(f" {identifier}: {option_value!r}")
diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml
index ff6b5ea7..d4b210ce 100644
--- a/cibuildwheel/resources/build-platforms.toml
+++ b/cibuildwheel/resources/build-platforms.toml
@@ -81,12 +81,12 @@ python_configurations = [
{ identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" },
{ identifier = "cp39-macosx_arm64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" },
{ identifier = "cp39-macosx_universal2", version = "3.9", url = "https://www.python.org/ftp/python/3.9.13/python-3.9.13-macos11.pkg" },
- { identifier = "cp310-macosx_x86_64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.6/python-3.10.6-macos11.pkg" },
- { identifier = "cp310-macosx_arm64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.6/python-3.10.6-macos11.pkg" },
- { identifier = "cp310-macosx_universal2", version = "3.10", url = "https://www.python.org/ftp/python/3.10.6/python-3.10.6-macos11.pkg" },
- { identifier = "cp311-macosx_x86_64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.0rc1-macos11.pkg" },
- { identifier = "cp311-macosx_arm64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.0rc1-macos11.pkg" },
- { identifier = "cp311-macosx_universal2", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.0rc1-macos11.pkg" },
+ { identifier = "cp310-macosx_x86_64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.7/python-3.10.7-macos11.pkg" },
+ { identifier = "cp310-macosx_arm64", version = "3.10", url = "https://www.python.org/ftp/python/3.10.7/python-3.10.7-macos11.pkg" },
+ { identifier = "cp310-macosx_universal2", version = "3.10", url = "https://www.python.org/ftp/python/3.10.7/python-3.10.7-macos11.pkg" },
+ { identifier = "cp311-macosx_x86_64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.0rc2-macos11.pkg" },
+ { identifier = "cp311-macosx_arm64", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.0rc2-macos11.pkg" },
+ { identifier = "cp311-macosx_universal2", version = "3.11", url = "https://www.python.org/ftp/python/3.11.0/python-3.11.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.9-osx64.tar.bz2" },
{ identifier = "pp39-macosx_x86_64", version = "3.9", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.9-osx64.tar.bz2" },
@@ -102,13 +102,13 @@ python_configurations = [
{ identifier = "cp38-win_amd64", version = "3.8.10", arch = "64" },
{ identifier = "cp39-win32", version = "3.9.13", arch = "32" },
{ identifier = "cp39-win_amd64", version = "3.9.13", arch = "64" },
- { identifier = "cp310-win32", version = "3.10.6", arch = "32" },
- { identifier = "cp310-win_amd64", version = "3.10.6", arch = "64" },
- { identifier = "cp311-win32", version = "3.11.0-rc1", arch = "32" },
- { identifier = "cp311-win_amd64", version = "3.11.0-rc1", arch = "64" },
+ { identifier = "cp310-win32", version = "3.10.7", arch = "32" },
+ { identifier = "cp310-win_amd64", version = "3.10.7", arch = "64" },
+ { identifier = "cp311-win32", version = "3.11.0-rc2", arch = "32" },
+ { identifier = "cp311-win_amd64", version = "3.11.0-rc2", arch = "64" },
{ identifier = "cp39-win_arm64", version = "3.9.10", arch = "ARM64" },
- { identifier = "cp310-win_arm64", version = "3.10.6", arch = "ARM64" },
- { identifier = "cp311-win_arm64", version = "3.11.0-rc1", arch = "ARM64" },
+ { identifier = "cp310-win_arm64", version = "3.10.7", arch = "ARM64" },
+ { identifier = "cp311-win_arm64", version = "3.11.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.9-win64.zip" },
{ identifier = "pp39-win_amd64", version = "3.9", arch = "64", url = "https://downloads.python.org/pypy/pypy3.9-v7.3.9-win64.zip" },
diff --git a/cibuildwheel/resources/constraints-python310.txt b/cibuildwheel/resources/constraints-python310.txt
index be1480a4..ec47c279 100644
--- a/cibuildwheel/resources/constraints-python310.txt
+++ b/cibuildwheel/resources/constraints-python310.txt
@@ -14,7 +14,7 @@ platformdirs==2.5.2
# via virtualenv
typing-extensions==4.3.0
# via delocate
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints-python311.txt b/cibuildwheel/resources/constraints-python311.txt
index 51136b16..748a80a6 100644
--- a/cibuildwheel/resources/constraints-python311.txt
+++ b/cibuildwheel/resources/constraints-python311.txt
@@ -14,7 +14,7 @@ platformdirs==2.5.2
# via virtualenv
typing-extensions==4.3.0
# via delocate
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints-python36.txt b/cibuildwheel/resources/constraints-python36.txt
index 00956c49..41b899a8 100644
--- a/cibuildwheel/resources/constraints-python36.txt
+++ b/cibuildwheel/resources/constraints-python36.txt
@@ -20,7 +20,7 @@ typing-extensions==4.1.1
# via
# delocate
# importlib-metadata
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints-python37.txt b/cibuildwheel/resources/constraints-python37.txt
index 49015dbd..076653a1 100644
--- a/cibuildwheel/resources/constraints-python37.txt
+++ b/cibuildwheel/resources/constraints-python37.txt
@@ -18,7 +18,7 @@ typing-extensions==4.3.0
# via
# delocate
# importlib-metadata
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints-python38.txt b/cibuildwheel/resources/constraints-python38.txt
index 0eb2b244..242f07d4 100644
--- a/cibuildwheel/resources/constraints-python38.txt
+++ b/cibuildwheel/resources/constraints-python38.txt
@@ -14,7 +14,7 @@ platformdirs==2.5.2
# via virtualenv
typing-extensions==4.3.0
# via delocate
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints-python39.txt b/cibuildwheel/resources/constraints-python39.txt
index 0b7e373d..160fef75 100644
--- a/cibuildwheel/resources/constraints-python39.txt
+++ b/cibuildwheel/resources/constraints-python39.txt
@@ -14,7 +14,7 @@ platformdirs==2.5.2
# via virtualenv
typing-extensions==4.3.0
# via delocate
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/constraints.txt b/cibuildwheel/resources/constraints.txt
index 51136b16..748a80a6 100644
--- a/cibuildwheel/resources/constraints.txt
+++ b/cibuildwheel/resources/constraints.txt
@@ -14,7 +14,7 @@ platformdirs==2.5.2
# via virtualenv
typing-extensions==4.3.0
# via delocate
-virtualenv==20.16.4
+virtualenv==20.16.5
# via -r cibuildwheel/resources/constraints.in
wheel==0.37.1
# via
diff --git a/cibuildwheel/resources/pinned_docker_images.cfg b/cibuildwheel/resources/pinned_docker_images.cfg
index f3047929..486aae09 100644
--- a/cibuildwheel/resources/pinned_docker_images.cfg
+++ b/cibuildwheel/resources/pinned_docker_images.cfg
@@ -1,49 +1,49 @@
[x86_64]
-manylinux1 = quay.io/pypa/manylinux1_x86_64:2022-09-04-d1c2903
+manylinux1 = quay.io/pypa/manylinux1_x86_64:2022-09-18-e2e56b7
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2022-09-04-870f6a2
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2022-09-18-2b8b451
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_x86_64:2022-09-18-2b8b451
[i686]
-manylinux1 = quay.io/pypa/manylinux1_i686:2022-09-04-d1c2903
+manylinux1 = quay.io/pypa/manylinux1_i686:2022-09-18-e2e56b7
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-09-04-870f6a2
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-09-18-2b8b451
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_i686:2022-09-18-2b8b451
[pypy_x86_64]
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2022-08-05-4535177
-manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_x86_64:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_x86_64:2022-09-18-2b8b451
[pypy_i686]
manylinux2010 = quay.io/pypa/manylinux2010_i686:2022-08-05-4535177
-manylinux2014 = quay.io/pypa/manylinux2014_i686:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_i686:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_i686:2022-09-18-2b8b451
[aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2022-09-04-870f6a2
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2022-09-18-2b8b451
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_aarch64:2022-09-18-2b8b451
[ppc64le]
-manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2022-09-04-870f6a2
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_ppc64le:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_ppc64le:2022-09-18-2b8b451
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_ppc64le:2022-09-18-2b8b451
[s390x]
-manylinux2014 = quay.io/pypa/manylinux2014_s390x:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2022-09-04-870f6a2
-musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_s390x:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_s390x:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_s390x:2022-09-18-2b8b451
+musllinux_1_1 = quay.io/pypa/musllinux_1_1_s390x:2022-09-18-2b8b451
[pypy_aarch64]
-manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2022-09-04-870f6a2
-manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-09-04-870f6a2
-manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2022-09-04-870f6a2
+manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2022-09-18-2b8b451
+manylinux_2_24 = quay.io/pypa/manylinux_2_24_aarch64:2022-09-18-2b8b451
+manylinux_2_28 = quay.io/pypa/manylinux_2_28_aarch64:2022-09-18-2b8b451
diff --git a/cibuildwheel/resources/virtualenv.toml b/cibuildwheel/resources/virtualenv.toml
index 1c277d73..0fbf028c 100644
--- a/cibuildwheel/resources/virtualenv.toml
+++ b/cibuildwheel/resources/virtualenv.toml
@@ -1,2 +1,2 @@
-version = "20.16.4"
-url = "https://github.com/pypa/get-virtualenv/blob/20.16.4/public/virtualenv.pyz?raw=true"
+version = "20.16.5"
+url = "https://github.com/pypa/get-virtualenv/blob/20.16.5/public/virtualenv.pyz?raw=true"
diff --git a/cibuildwheel/typing.py b/cibuildwheel/typing.py
index a546d7bf..3ffa5476 100644
--- a/cibuildwheel/typing.py
+++ b/cibuildwheel/typing.py
@@ -10,6 +10,10 @@ if sys.version_info < (3, 8):
else:
from typing import Final, Literal, OrderedDict, Protocol, TypedDict
+if sys.version_info < (3, 11):
+ from typing_extensions import NotRequired
+else:
+ from typing import NotRequired
__all__ = (
"Final",
@@ -26,6 +30,7 @@ __all__ = (
"OrderedDict",
"Union",
"assert_never",
+ "NotRequired",
)
diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py
index 4b3d4fb9..01db05ec 100644
--- a/cibuildwheel/util.py
+++ b/cibuildwheel/util.py
@@ -63,13 +63,13 @@ __all__ = [
"split_config_settings",
]
-resources_dir: Final = Path(__file__).parent / "resources"
+resources_dir: Final[Path] = Path(__file__).parent / "resources"
-install_certifi_script: Final = resources_dir / "install_certifi.py"
+install_certifi_script: Final[Path] = resources_dir / "install_certifi.py"
BuildFrontend = Literal["pip", "build"]
-MANYLINUX_ARCHS: Final = (
+MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64",
"i686",
"pypy_x86_64",
@@ -80,7 +80,7 @@ MANYLINUX_ARCHS: Final = (
"pypy_i686",
)
-MUSLLINUX_ARCHS: Final = (
+MUSLLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64",
"i686",
"aarch64",
@@ -88,10 +88,12 @@ MUSLLINUX_ARCHS: Final = (
"s390x",
)
-DEFAULT_CIBW_CACHE_PATH: Final = user_cache_path(appname="cibuildwheel", appauthor="pypa")
-CIBW_CACHE_PATH: Final = Path(os.environ.get("CIBW_CACHE_PATH", DEFAULT_CIBW_CACHE_PATH)).resolve()
+DEFAULT_CIBW_CACHE_PATH: Final[Path] = user_cache_path(appname="cibuildwheel", appauthor="pypa")
+CIBW_CACHE_PATH: Final[Path] = Path(
+ os.environ.get("CIBW_CACHE_PATH", DEFAULT_CIBW_CACHE_PATH)
+).resolve()
-IS_WIN: Final = sys.platform.startswith("win")
+IS_WIN: Final[bool] = sys.platform.startswith("win")
@overload
@@ -145,7 +147,7 @@ def shell(*commands: str, env: dict[str, str] | None = None, cwd: PathOrStr | No
subprocess.run(command, env=env, cwd=cwd, shell=True, check=True)
-def format_safe(template: str, **kwargs: Any) -> str:
+def format_safe(template: str, **kwargs: str | os.PathLike[str]) -> str:
"""
Works similarly to `template.format(**kwargs)`, except that unmatched
fields in `template` are passed through untouched.
@@ -173,11 +175,9 @@ def format_safe(template: str, **kwargs: Any) -> str:
re.VERBOSE,
)
- # we use a function for repl to prevent re.sub interpreting backslashes
- # in repl as escape sequences.
result = re.sub(
pattern=find_pattern,
- repl=lambda _: str(value), # pylint: disable=cell-var-from-loop
+ repl=str(value).replace("\\", r"\\"),
string=result,
)
diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py
index d256c27c..ede27bb5 100644
--- a/cibuildwheel/windows.py
+++ b/cibuildwheel/windows.py
@@ -235,7 +235,8 @@ def setup_python(
assert python_configuration.url is not None
base_python = install_pypy(tmp, python_configuration.arch, python_configuration.url)
else:
- raise ValueError("Unknown Python implementation")
+ msg = "Unknown Python implementation"
+ raise ValueError(msg)
assert base_python.exists()
log.step("Setting up build environment...")
diff --git a/docs/changelog.md b/docs/changelog.md
index 2b465a91..8ed60e82 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -4,6 +4,32 @@ title: Changelog
# Changelog
+### v2.10.2
+
+_25 September 2022_
+
+- 🐛 Fix a bug that caused `win32` identifiers to fail when used with `--only`. (#1282)
+- 🐛 Fix computation of `auto`/`auto64`/`auto32` archs when targeting a different platform to the one that you're running cibuildwheel on. (#1266)
+- 📚 Fix an mistake in the 'how it works' diagram. (#1274)
+
+### v2.10.1
+
+_18 September 2022_
+
+- 🐛 Fix a bug that stopped environment variables specified in TOML from being expanded. (#1273)
+
+### v2.10.0
+
+_13 September 2022_
+
+- 🌟 Adds support for [building wheels on Cirrus CI](https://cibuildwheel.readthedocs.io/en/stable/setup/#cirrus-ci). This is exciting for us, as it's the first public CI platform that natively supports macOS Apple Silicon (aka. M1, `arm64`) runners. As such, it's the first platform that you can natively build _and test_ macOS `arm64` wheels. It also has native Linux ARM (aarch64) runners, for fast, native builds there. (#1191)
+- 🌟 Adds support for running cibuildwheel on Apple Silicon machines. For a while, we've supported cross-compilation of Apple Silicon wheels on `x86_64`, but now that we have Cirrus CI we can run our test suite and officially support running cibuildwheel on `arm64`. (#1191)
+- ✨ Adds the `--only` [command line option](https://cibuildwheel.readthedocs.io/en/stable/options/#command-line), to specify a single build to run. Previously, it could be cumbersome to set all the build selection options to target a specific build - for example, you might have to run something like `CIBW_BUILD=cp39-manylinux_x86_64 cibuildwheel --platform linux --archs x86_64`. The new `--only` option overrides all the build selection options to simplify running a single build, which now looks like `cibuildwheel --only cp39-manylinux_x86_64`. (#1098)
+- ✨ Adds the [`CIBW_CONFIG_SETTINGS`](https://cibuildwheel.readthedocs.io/en/stable/options/#config-settings) option, so you can pass arguments to your package's build backend (#1244)
+- 🛠 Updates the CPython 3.11 version to the latest release candidate - v3.11.0rc2. (#1265)
+- 🐛 Fix a bug that can cause a RecursionError on Windows when building from an sdist. (#1253)
+- 🛠 Add support for the s390x architecture on manylinux_2_28 (#1255)
+
### v2.9.0
_11 August 2022_
@@ -29,9 +55,10 @@ _5 July 2022_
- ✨ You can now run cibuildwheel on Podman, as an alternate container engine to Docker (which remains the default). This is useful in environments where a Docker daemon isn't available, for example, it can be run inside a Docker container, or without root access. To use Podman, set the [`CIBW_CONTAINER_ENGINE`](https://cibuildwheel.readthedocs.io/en/stable/options/#container-engine) option. (#966)
- ✨ Adds support for building `py3-none-{platform}` wheels. This works the same as ABI3 - wheels won't be rebuilt, but tests will still be run across all selected versions of Python.
- > These wheels contain native extension code, but don't use the Python APIs. Typically, they're bridged to Python using a FFI module like [ctypes](https://docs.python.org/3/library/ctypes.html) or [cffi](https://cffi.readthedocs.io/en/latest/). Because they don't use Python ABI, the wheels are more compatible - they work across many Python versions.
+ These wheels contain native extension code, but don't use the Python APIs. Typically, they're bridged to Python using a FFI module like [ctypes](https://docs.python.org/3/library/ctypes.html) or [cffi](https://cffi.readthedocs.io/en/latest/). Because they don't use Python ABI, the wheels are more compatible - they work across many Python versions.
+
+ Check out this [example ctypes project](https://github.com/joerick/python-ctypes-package-sample) to see an example of how it works. (#1151)
- Check out this [example ctypes project](https://github.com/joerick/python-ctypes-package-sample) to see an example of how it works. (#1151)
- 🛠 cibuildwheel will now error if multiple builds in a single run produce the same wheel filename, as this indicates a misconfiguration. (#1152)
- 📚 A few docs improvements and updates to keep things up-to-date.
@@ -716,6 +743,18 @@ _31 March 2017_
- 🌟 First public release!
+
+