From 97ddab582875b004b041919ff3dba43d87eb4f24 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 2 Jan 2021 11:29:11 -0500 Subject: [PATCH 1/8] refactor: identifiers in a file --- cibuildwheel/__main__.py | 20 +++++-- cibuildwheel/linux.py | 44 +++----------- cibuildwheel/macos.py | 21 ++----- cibuildwheel/resources/build-platforms.toml | 63 +++++++++++++++++++++ cibuildwheel/util.py | 8 +++ cibuildwheel/windows.py | 33 ++++------- unit_test/build_ids_test.py | 28 +++++++++ 7 files changed, 136 insertions(+), 81 deletions(-) create mode 100644 cibuildwheel/resources/build-platforms.toml create mode 100644 unit_test/build_ids_test.py diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 8f76c6a3a..a770a2569 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -20,6 +20,7 @@ Unbuffered, detect_ci_provider, resources_dir, + read_python_configs, ) @@ -120,6 +121,10 @@ def main() -> None: file=sys.stderr) exit(2) + if platform not in {"linux", "macos", "windows"}: + print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr) + exit(2) + package_dir = Path(args.package_dir) output_dir = Path(args.output_dir) @@ -215,6 +220,8 @@ def main() -> None: manylinux_images[build_platform] = image + python_configs = read_python_configs(resources_dir / 'build-platforms.toml', platform) + build_options = BuildOptions( architectures=archs, package_dir=package_dir, @@ -231,6 +238,7 @@ def main() -> None: environment=environment, dependency_constraints=dependency_constraints, manylinux_images=manylinux_images, + python_configs=python_configs, ) # Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print' @@ -247,9 +255,6 @@ def main() -> None: cibuildwheel.windows.build(build_options) elif platform == 'macos': cibuildwheel.macos.build(build_options) - else: - print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr) - exit(2) def detect_obsolete_options() -> None: @@ -302,13 +307,16 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None: def print_build_identifiers( platform: str, build_selector: BuildSelector, architectures: Set[Architecture] ) -> None: + + python_configs = read_python_configs(resources_dir / "build-platforms.toml", platform) + python_configurations: List[Any] = [] if platform == 'linux': - python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures) + python_configurations = cibuildwheel.linux.get_python_configurations(python_configs, build_selector, architectures) elif platform == 'windows': - python_configurations = cibuildwheel.windows.get_python_configurations(build_selector, architectures) + python_configurations = cibuildwheel.windows.get_python_configurations(python_configs, build_selector, architectures) elif platform == 'macos': - python_configurations = cibuildwheel.macos.get_python_configurations(build_selector) + python_configurations = cibuildwheel.macos.get_python_configurations(python_configs, build_selector) for config in python_configurations: print(config.identifier) diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 7da89aeea..1db959d3c 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -2,7 +2,7 @@ import sys import textwrap from pathlib import Path, PurePath -from typing import List, NamedTuple, Set +from typing import List, NamedTuple, Dict, Set from .docker_container import DockerContainer from .logger import log @@ -29,42 +29,12 @@ def path(self) -> PurePath: def get_python_configurations( - build_selector: BuildSelector, architectures: Set[Architecture] + python_configs: List[Dict[str, str]], + build_selector: BuildSelector, + architectures: Set[Architecture] ) -> List[PythonConfiguration]: - python_configurations = [ - PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27m'), - PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27mu'), - PythonConfiguration(version='3.5', identifier='cp35-manylinux_x86_64', path_str='/opt/python/cp35-cp35m'), - PythonConfiguration(version='3.6', identifier='cp36-manylinux_x86_64', path_str='/opt/python/cp36-cp36m'), - PythonConfiguration(version='3.7', identifier='cp37-manylinux_x86_64', path_str='/opt/python/cp37-cp37m'), - PythonConfiguration(version='3.8', identifier='cp38-manylinux_x86_64', path_str='/opt/python/cp38-cp38'), - PythonConfiguration(version='3.9', identifier='cp39-manylinux_x86_64', path_str='/opt/python/cp39-cp39'), - PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27m'), - PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27mu'), - PythonConfiguration(version='3.5', identifier='cp35-manylinux_i686', path_str='/opt/python/cp35-cp35m'), - PythonConfiguration(version='3.6', identifier='cp36-manylinux_i686', path_str='/opt/python/cp36-cp36m'), - PythonConfiguration(version='3.7', identifier='cp37-manylinux_i686', path_str='/opt/python/cp37-cp37m'), - PythonConfiguration(version='3.8', identifier='cp38-manylinux_i686', path_str='/opt/python/cp38-cp38'), - PythonConfiguration(version='3.9', identifier='cp39-manylinux_i686', path_str='/opt/python/cp39-cp39'), - PythonConfiguration(version='2.7', identifier='pp27-manylinux_x86_64', path_str='/opt/python/pp27-pypy_73'), - PythonConfiguration(version='3.6', identifier='pp36-manylinux_x86_64', path_str='/opt/python/pp36-pypy36_pp73'), - PythonConfiguration(version='3.7', identifier='pp37-manylinux_x86_64', path_str='/opt/python/pp37-pypy37_pp73'), - PythonConfiguration(version='3.5', identifier='cp35-manylinux_aarch64', path_str='/opt/python/cp35-cp35m'), - PythonConfiguration(version='3.6', identifier='cp36-manylinux_aarch64', path_str='/opt/python/cp36-cp36m'), - PythonConfiguration(version='3.7', identifier='cp37-manylinux_aarch64', path_str='/opt/python/cp37-cp37m'), - PythonConfiguration(version='3.8', identifier='cp38-manylinux_aarch64', path_str='/opt/python/cp38-cp38'), - PythonConfiguration(version='3.9', identifier='cp39-manylinux_aarch64', path_str='/opt/python/cp39-cp39'), - PythonConfiguration(version='3.5', identifier='cp35-manylinux_ppc64le', path_str='/opt/python/cp35-cp35m'), - PythonConfiguration(version='3.6', identifier='cp36-manylinux_ppc64le', path_str='/opt/python/cp36-cp36m'), - PythonConfiguration(version='3.7', identifier='cp37-manylinux_ppc64le', path_str='/opt/python/cp37-cp37m'), - PythonConfiguration(version='3.8', identifier='cp38-manylinux_ppc64le', path_str='/opt/python/cp38-cp38'), - PythonConfiguration(version='3.9', identifier='cp39-manylinux_ppc64le', path_str='/opt/python/cp39-cp39'), - PythonConfiguration(version='3.5', identifier='cp35-manylinux_s390x', path_str='/opt/python/cp35-cp35m'), - PythonConfiguration(version='3.6', identifier='cp36-manylinux_s390x', path_str='/opt/python/cp36-cp36m'), - PythonConfiguration(version='3.7', identifier='cp37-manylinux_s390x', path_str='/opt/python/cp37-cp37m'), - PythonConfiguration(version='3.8', identifier='cp38-manylinux_s390x', path_str='/opt/python/cp38-cp38'), - PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'), - ] + + python_configurations = [PythonConfiguration(**item) for item in python_configs] # return all configurations whose arch is in our `architectures` set, # and match the build/skip rules @@ -88,7 +58,7 @@ def build(options: BuildOptions) -> None: exit(2) assert options.manylinux_images is not None - python_configurations = get_python_configurations(options.build_selector, options.architectures) + python_configurations = get_python_configurations(options.python_configs, options.build_selector, options.architectures) platforms = [ ('cp', 'manylinux_x86_64', options.manylinux_images['x86_64']), ('cp', 'manylinux_i686', options.manylinux_images['i686']), diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 519c8bc16..c62e90ad4 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -39,20 +39,11 @@ class PythonConfiguration(NamedTuple): url: str -def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]: - python_configurations = [ - # CPython - PythonConfiguration(version='2.7', identifier='cp27-macosx_x86_64', url='https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg'), - PythonConfiguration(version='3.5', identifier='cp35-macosx_x86_64', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'), - PythonConfiguration(version='3.6', identifier='cp36-macosx_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'), - PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg'), - PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg'), - PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg'), - # PyPy - PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'), - PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'), - PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'), - ] +def get_python_configurations( + python_configs: List[Dict[str, str]], + build_selector: BuildSelector) -> List[PythonConfiguration]: + + python_configurations = [PythonConfiguration(**item) for item in python_configs] # skip builds as required return [c for c in python_configurations if build_selector(c.identifier)] @@ -207,7 +198,7 @@ def build(options: BuildOptions) -> None: before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir) call([before_all_prepared], shell=True, env=env) - python_configurations = get_python_configurations(options.build_selector) + python_configurations = get_python_configurations(options.python_configs, options.build_selector) for config in python_configurations: log.build_start(config.identifier) diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml new file mode 100644 index 000000000..2298e3f2d --- /dev/null +++ b/cibuildwheel/resources/build-platforms.toml @@ -0,0 +1,63 @@ +[tool.cibw.build-platforms] +linux = [ + { identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27m" }, + { identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27mu" }, + { identifier = "cp35-manylinux_x86_64", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, + { identifier = "cp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { identifier = "cp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, + { identifier = "cp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, + { identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27m" }, + { identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27mu" }, + { identifier = "cp35-manylinux_i686", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, + { identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" }, + { identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" }, + { identifier = "pp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/pp27-pypy_73" }, + { identifier = "pp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/pp36-pypy36_pp73" }, + { identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" }, + { identifier = "cp35-manylinux_aarch64", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, + { identifier = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" }, + { identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" }, + { identifier = "cp35-manylinux_ppc64le", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, + { identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" }, + { identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" }, + { identifier = "cp35-manylinux_s390x", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, + { identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" }, + { identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" }, + { identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" }, + { identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" }, +] +macos = [ + { identifier = "cp27-macosx_x86_64", version = "2.7", url = "https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg" }, + { identifier = "cp35-macosx_x86_64", version = "3.5", url = "https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg" }, + { identifier = "cp36-macosx_x86_64", version = "3.6", url = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg" }, + { identifier = "cp37-macosx_x86_64", version = "3.7", url = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg" }, + { identifier = "cp38-macosx_x86_64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg" }, + { identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg" }, + { identifier = "pp27-macosx_x86_64", version = "2.7", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2" }, + { identifier = "pp36-macosx_x86_64", version = "3.6", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2" }, + { identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" }, +] +windows = [ + { identifier = "cp27-win32", version = "2.7.18", arch = "32" }, + { identifier = "cp27-win_amd64", version = "2.7.18", arch = "64" }, + { identifier = "cp35-win32", version = "3.5.4", arch = "32" }, + { identifier = "cp35-win_amd64", version = "3.5.4", arch = "64" }, + { identifier = "cp36-win32", version = "3.6.8", arch = "32" }, + { identifier = "cp36-win_amd64", version = "3.6.8", arch = "64" }, + { identifier = "cp37-win32", version = "3.7.9", arch = "32" }, + { identifier = "cp37-win_amd64", version = "3.7.9", arch = "64" }, + { identifier = "cp38-win32", version = "3.8.7", arch = "32" }, + { identifier = "cp38-win_amd64", version = "3.8.7", arch = "64" }, + { identifier = "cp39-win32", version = "3.9.1", arch = "32" }, + { identifier = "cp39-win_amd64", version = "3.9.1", arch = "64" }, + { identifier = "pp27-win32", version = "2.7", arch = "32", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip" }, + { identifier = "pp36-win32", version = "3.6", arch = "32", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip" }, + { identifier = "pp37-win32", version = "3.7", arch = "32", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip" }, +] diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 6435252f1..3129d9228 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -13,6 +13,7 @@ from typing import Dict, List, NamedTuple, Optional, Set import certifi +import toml from .environment import ParsedEnvironment from .typing import PathOrStr @@ -42,6 +43,12 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]: return [] +def read_python_configs(input_path: PathOrStr, config: str) -> List[Dict[str, str]]: + loaded_file = toml.load(input_path) + results: List[Dict[str, str]] = list(loaded_file["tool"]["cibw"]["build-platforms"][config]) + return results + + class BuildSelector: def __init__(self, build_config: str, skip_config: str): self.build_patterns = build_config.split() @@ -188,6 +195,7 @@ class BuildOptions(NamedTuple): test_requires: List[str] test_extras: str build_verbosity: int + python_configs: List[Dict[str, str]] resources_dir = Path(__file__).resolve().parent / 'resources' diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 355fe0554..96a80ffec 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -52,35 +52,22 @@ class PythonConfiguration(NamedTuple): version: str arch: str identifier: str - url: Optional[str] + url: Optional[str] = None -def get_python_configurations(build_selector: BuildSelector, architectures: Set[Architecture]) -> List[PythonConfiguration]: +def get_python_configurations( + python_configs: List[Dict[str, str]], + build_selector: BuildSelector, + architectures: Set[Architecture], +) -> List[PythonConfiguration]: + + python_configurations = [PythonConfiguration(**item) for item in python_configs] + map_arch = { '32': Architecture.x86, '64': Architecture.AMD64, } - python_configurations = [ - # CPython - PythonConfiguration(version='2.7.18', arch='32', identifier='cp27-win32', url=None), - PythonConfiguration(version='2.7.18', arch='64', identifier='cp27-win_amd64', url=None), - PythonConfiguration(version='3.5.4', arch='32', identifier='cp35-win32', url=None), - PythonConfiguration(version='3.5.4', arch='64', identifier='cp35-win_amd64', url=None), - PythonConfiguration(version='3.6.8', arch='32', identifier='cp36-win32', url=None), - PythonConfiguration(version='3.6.8', arch='64', identifier='cp36-win_amd64', url=None), - PythonConfiguration(version='3.7.9', arch='32', identifier='cp37-win32', url=None), - PythonConfiguration(version='3.7.9', arch='64', identifier='cp37-win_amd64', url=None), - PythonConfiguration(version='3.8.7', arch='32', identifier='cp38-win32', url=None), - PythonConfiguration(version='3.8.7', arch='64', identifier='cp38-win_amd64', url=None), - PythonConfiguration(version='3.9.1', arch='32', identifier='cp39-win32', url=None), - PythonConfiguration(version='3.9.1', arch='64', identifier='cp39-win_amd64', url=None), - # PyPy - PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip'), - PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip'), - PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip'), - ] - if IS_RUNNING_ON_TRAVIS: # cannot install VCForPython27.msi which is needed for compiling C software # try with (and similar): msiexec /i VCForPython27.msi ALLUSERS=1 ACCEPT=YES /passive @@ -230,7 +217,7 @@ def build(options: BuildOptions) -> None: before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir) shell(before_all_prepared, env=env) - python_configurations = get_python_configurations(options.build_selector, options.architectures) + python_configurations = get_python_configurations(options.python_configs, options.build_selector, options.architectures) for config in python_configurations: log.build_start(config.identifier) diff --git a/unit_test/build_ids_test.py b/unit_test/build_ids_test.py new file mode 100644 index 000000000..99c5b57ed --- /dev/null +++ b/unit_test/build_ids_test.py @@ -0,0 +1,28 @@ +import toml +from toml.encoder import TomlEncoder + +from cibuildwheel.util import resources_dir + + +class InlineArrayDictEncoder(TomlEncoder): + def dump_sections(self, o: dict, sup: str): + if all(isinstance(a, list) for a in o.values()): + val = "" + for k, v in o.items(): + inner = ",\n ".join(self.dump_inline_table(d_i).strip() for d_i in v) + val += f"{k} = [\n {inner},\n]\n" + return val, self._dict() + else: + return super().dump_sections(o, sup) + + +def test_compare_configs(): + with open(resources_dir / "build-platforms.toml") as f: + txt = f.read() + + dict_txt = toml.loads(txt) + + new_txt = toml.dumps(dict_txt, encoder=InlineArrayDictEncoder()) + print(new_txt) + + assert new_txt == txt From b1f1f23ddd746689a685abbb5bca943844dab042 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Tue, 5 Jan 2021 21:40:09 -0500 Subject: [PATCH 2/8] chore: more typing --- cibuildwheel/__main__.py | 13 ++++++++++--- cibuildwheel/linux.py | 2 +- cibuildwheel/typing.py | 17 ++++++++++++++++- cibuildwheel/util.py | 14 ++++---------- setup.cfg | 4 ++++ 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index a770a2569..ef6f03446 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -12,6 +12,7 @@ import cibuildwheel.macos import cibuildwheel.windows from cibuildwheel.environment import EnvironmentParseError, parse_environment +from cibuildwheel.typing import PLATFORMS, PlatStr, assert_never from cibuildwheel.util import ( Architecture, BuildOptions, @@ -19,8 +20,8 @@ DependencyConstraints, Unbuffered, detect_ci_provider, - resources_dir, read_python_configs, + resources_dir, ) @@ -47,6 +48,8 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None def main() -> None: + platform: PlatStr + parser = argparse.ArgumentParser( description='Build wheels for all the platforms.', epilog=''' @@ -121,7 +124,7 @@ def main() -> None: file=sys.stderr) exit(2) - if platform not in {"linux", "macos", "windows"}: + if platform not in PLATFORMS: print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr) exit(2) @@ -132,8 +135,10 @@ def main() -> None: repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}' elif platform == 'macos': repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs x86_64 -w {dest_dir} {wheel}' - else: + elif platform == 'windows': repair_command_default = '' + else: + assert_never(platform) build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '') environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='') @@ -255,6 +260,8 @@ def main() -> None: cibuildwheel.windows.build(build_options) elif platform == 'macos': cibuildwheel.macos.build(build_options) + else: + assert_never(platform) def detect_obsolete_options() -> None: diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 1db959d3c..3d7e6a619 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -2,7 +2,7 @@ import sys import textwrap from pathlib import Path, PurePath -from typing import List, NamedTuple, Dict, Set +from typing import Dict, List, NamedTuple, Set from .docker_container import DockerContainer from .logger import log diff --git a/cibuildwheel/typing.py b/cibuildwheel/typing.py index ffe8afb68..8c07d282f 100644 --- a/cibuildwheel/typing.py +++ b/cibuildwheel/typing.py @@ -1,6 +1,13 @@ import os import subprocess -from typing import TYPE_CHECKING, Union +import sys +from typing import TYPE_CHECKING, NoReturn, Set, Union + +if sys.version_info < (3, 8): + from typing_extensions import Final, Literal +else: + from typing import Final, Literal + if TYPE_CHECKING: PopenBytes = subprocess.Popen[bytes] @@ -8,3 +15,11 @@ else: PopenBytes = subprocess.Popen PathOrStr = Union[str, "os.PathLike[str]"] + + +PlatStr = Literal["linux", "macos", "windows"] +PLATFORMS: Final[Set[PlatStr]] = {"linux", "macos", "windows"} + + +def assert_never(value: NoReturn) -> NoReturn: + assert False, f'Unhandled value: {value} ({type(value).__name__})' # noqa: B011 diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 3129d9228..fc4d50a0c 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -3,7 +3,6 @@ import platform as platform_module import re import ssl -import sys import textwrap import urllib.request from enum import Enum @@ -16,12 +15,7 @@ import toml from .environment import ParsedEnvironment -from .typing import PathOrStr - -if sys.version_info < (3, 8): - from typing_extensions import Literal -else: - from typing import Literal +from .typing import PathOrStr, PlatStr def prepare_command(command: str, **kwargs: PathOrStr) -> str: @@ -158,7 +152,7 @@ def __lt__(self, other: "Architecture") -> bool: return self.value < other.value @staticmethod - def parse_config(config: str, platform: str) -> 'Set[Architecture]': + def parse_config(config: str, platform: PlatStr) -> 'Set[Architecture]': result = set() for arch_str in re.split(r'[\s,]+', config): if arch_str == 'auto': @@ -168,7 +162,7 @@ def parse_config(config: str, platform: str) -> 'Set[Architecture]': return result @staticmethod - def auto_archs(platform: str) -> 'Set[Architecture]': + def auto_archs(platform: PlatStr) -> 'Set[Architecture]': native_architecture = Architecture(platform_module.machine()) result = {native_architecture} if platform == 'linux' and native_architecture == Architecture.x86_64: @@ -263,7 +257,7 @@ def detect_ci_provider() -> Optional[CIProvider]: def allowed_architectures_check( - name: Literal['linux', 'macos', 'windows'], + name: PlatStr, options: BuildOptions, ) -> None: diff --git a/setup.cfg b/setup.cfg index 3ba3b866d..2b23a5e90 100644 --- a/setup.cfg +++ b/setup.cfg @@ -112,6 +112,10 @@ ignore_missing_imports = True [mypy-bashlex.*] ignore_missing_imports = True +# Has type stubs, but no pyproject.toml or .pyi files in the wheel. +[mypy-toml.*] +ignore_missing_imports = True + [tool:isort] profile=black multi_line_output=3 From 9bb8c9538e783fb3d5d4151a85b1780e19bb8f4d Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Fri, 8 Jan 2021 21:54:55 -0500 Subject: [PATCH 3/8] refactor: PlatStr -> PlatformName --- cibuildwheel/__main__.py | 4 ++-- cibuildwheel/typing.py | 4 ++-- cibuildwheel/util.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index ef6f03446..88ed3720a 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -12,7 +12,7 @@ import cibuildwheel.macos import cibuildwheel.windows from cibuildwheel.environment import EnvironmentParseError, parse_environment -from cibuildwheel.typing import PLATFORMS, PlatStr, assert_never +from cibuildwheel.typing import PLATFORMS, PlatformName, assert_never from cibuildwheel.util import ( Architecture, BuildOptions, @@ -48,7 +48,7 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None def main() -> None: - platform: PlatStr + platform: PlatformName parser = argparse.ArgumentParser( description='Build wheels for all the platforms.', diff --git a/cibuildwheel/typing.py b/cibuildwheel/typing.py index 8c07d282f..03a1c7c1a 100644 --- a/cibuildwheel/typing.py +++ b/cibuildwheel/typing.py @@ -17,8 +17,8 @@ PathOrStr = Union[str, "os.PathLike[str]"] -PlatStr = Literal["linux", "macos", "windows"] -PLATFORMS: Final[Set[PlatStr]] = {"linux", "macos", "windows"} +PlatformName = Literal["linux", "macos", "windows"] +PLATFORMS: Final[Set[PlatformName]] = {"linux", "macos", "windows"} def assert_never(value: NoReturn) -> NoReturn: diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index fc4d50a0c..931b74104 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -15,7 +15,7 @@ import toml from .environment import ParsedEnvironment -from .typing import PathOrStr, PlatStr +from .typing import PathOrStr, PlatformName def prepare_command(command: str, **kwargs: PathOrStr) -> str: @@ -152,7 +152,7 @@ def __lt__(self, other: "Architecture") -> bool: return self.value < other.value @staticmethod - def parse_config(config: str, platform: PlatStr) -> 'Set[Architecture]': + def parse_config(config: str, platform: PlatformName) -> 'Set[Architecture]': result = set() for arch_str in re.split(r'[\s,]+', config): if arch_str == 'auto': @@ -162,7 +162,7 @@ def parse_config(config: str, platform: PlatStr) -> 'Set[Architecture]': return result @staticmethod - def auto_archs(platform: PlatStr) -> 'Set[Architecture]': + def auto_archs(platform: PlatformName) -> 'Set[Architecture]': native_architecture = Architecture(platform_module.machine()) result = {native_architecture} if platform == 'linux' and native_architecture == Architecture.x86_64: @@ -257,7 +257,7 @@ def detect_ci_provider() -> Optional[CIProvider]: def allowed_architectures_check( - name: PlatStr, + name: PlatformName, options: BuildOptions, ) -> None: From b54f6658ee0814e212acd08392daca629ffab9f2 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Fri, 8 Jan 2021 22:32:26 -0500 Subject: [PATCH 4/8] refactor: load in file, use importlib.resources --- cibuildwheel/__main__.py | 12 +++--------- cibuildwheel/linux.py | 15 +++++++++------ cibuildwheel/macos.py | 11 +++++++---- cibuildwheel/util.py | 14 ++++++++++---- cibuildwheel/windows.py | 12 +++++++----- setup.cfg | 1 + 6 files changed, 37 insertions(+), 28 deletions(-) diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 88ed3720a..5ca9c1049 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -20,7 +20,6 @@ DependencyConstraints, Unbuffered, detect_ci_provider, - read_python_configs, resources_dir, ) @@ -225,8 +224,6 @@ def main() -> None: manylinux_images[build_platform] = image - python_configs = read_python_configs(resources_dir / 'build-platforms.toml', platform) - build_options = BuildOptions( architectures=archs, package_dir=package_dir, @@ -243,7 +240,6 @@ def main() -> None: environment=environment, dependency_constraints=dependency_constraints, manylinux_images=manylinux_images, - python_configs=python_configs, ) # Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print' @@ -315,15 +311,13 @@ def print_build_identifiers( platform: str, build_selector: BuildSelector, architectures: Set[Architecture] ) -> None: - python_configs = read_python_configs(resources_dir / "build-platforms.toml", platform) - python_configurations: List[Any] = [] if platform == 'linux': - python_configurations = cibuildwheel.linux.get_python_configurations(python_configs, build_selector, architectures) + python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures) elif platform == 'windows': - python_configurations = cibuildwheel.windows.get_python_configurations(python_configs, build_selector, architectures) + python_configurations = cibuildwheel.windows.get_python_configurations(build_selector, architectures) elif platform == 'macos': - python_configurations = cibuildwheel.macos.get_python_configurations(python_configs, build_selector) + python_configurations = cibuildwheel.macos.get_python_configurations(build_selector) for config in python_configurations: print(config.identifier) diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 3d7e6a619..6573aa82f 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -2,7 +2,7 @@ import sys import textwrap from pathlib import Path, PurePath -from typing import Dict, List, NamedTuple, Set +from typing import List, NamedTuple, Set from .docker_container import DockerContainer from .logger import log @@ -15,6 +15,8 @@ allowed_architectures_check, get_build_verbosity_extra_flags, prepare_command, + read_python_configs, + resources_dir, ) @@ -29,12 +31,13 @@ def path(self) -> PurePath: def get_python_configurations( - python_configs: List[Dict[str, str]], build_selector: BuildSelector, architectures: Set[Architecture] ) -> List[PythonConfiguration]: - python_configurations = [PythonConfiguration(**item) for item in python_configs] + full_python_configs = read_python_configs('linux') + + python_configurations = [PythonConfiguration(**item) for item in full_python_configs] # return all configurations whose arch is in our `architectures` set, # and match the build/skip rules @@ -46,7 +49,7 @@ def get_python_configurations( def build(options: BuildOptions) -> None: - allowed_architectures_check("linux", options) + allowed_architectures_check('linux', options) try: subprocess.check_output(['docker', '--version']) @@ -58,7 +61,7 @@ def build(options: BuildOptions) -> None: exit(2) assert options.manylinux_images is not None - python_configurations = get_python_configurations(options.python_configs, options.build_selector, options.architectures) + python_configurations = get_python_configurations(options.build_selector, options.architectures) platforms = [ ('cp', 'manylinux_x86_64', options.manylinux_images['x86_64']), ('cp', 'manylinux_i686', options.manylinux_images['i686']), @@ -106,7 +109,7 @@ def build(options: BuildOptions) -> None: if config.identifier.startswith("pp"): # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if config.version == '2.7' else '' - patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' + patch_path = resources_dir / f'pypy_venv{patch_version}.patch' patch_docker_path = PurePath('/pypy_venv.patch') docker.copy_into(patch_path, patch_docker_path) try: diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index c62e90ad4..de9cd15e5 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -20,6 +20,8 @@ get_pip_script, install_certifi_script, prepare_command, + read_python_configs, + resources_dir, ) @@ -40,10 +42,11 @@ class PythonConfiguration(NamedTuple): def get_python_configurations( - python_configs: List[Dict[str, str]], build_selector: BuildSelector) -> List[PythonConfiguration]: - python_configurations = [PythonConfiguration(**item) for item in python_configs] + full_python_configs = read_python_configs('macos') + + python_configurations = [PythonConfiguration(**item) for item in full_python_configs] # skip builds as required return [c for c in python_configurations if build_selector(c.identifier)] @@ -106,7 +109,7 @@ def install_pypy(version: str, url: str) -> Path: call(['tar', '-C', '/tmp', '-xf', downloaded_tar_bz2]) # Patch PyPy to make sure headers get installed into a venv patch_version = '_27' if version == '2.7' else '' - patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch' + patch_path = resources_dir / f'pypy_venv{patch_version}.patch' call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path]) installation_bin_path = installation_path / 'bin' @@ -198,7 +201,7 @@ def build(options: BuildOptions) -> None: before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir) call([before_all_prepared], shell=True, env=env) - python_configurations = get_python_configurations(options.python_configs, options.build_selector) + python_configurations = get_python_configurations(options.build_selector) for config in python_configurations: log.build_start(config.identifier) diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 931b74104..b80a12905 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -3,6 +3,7 @@ import platform as platform_module import re import ssl +import sys import textwrap import urllib.request from enum import Enum @@ -17,6 +18,11 @@ from .environment import ParsedEnvironment from .typing import PathOrStr, PlatformName +if sys.version_info < (3, 9): + from importlib_resources import files +else: + from importlib.resources import files + def prepare_command(command: str, **kwargs: PathOrStr) -> str: ''' @@ -37,8 +43,9 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]: return [] -def read_python_configs(input_path: PathOrStr, config: str) -> List[Dict[str, str]]: - loaded_file = toml.load(input_path) +def read_python_configs(config: PlatformName) -> List[Dict[str, str]]: + input_file = files('cibuildwheel') / 'resources/build-platforms.toml' + loaded_file = toml.load(input_file) results: List[Dict[str, str]] = list(loaded_file["tool"]["cibw"]["build-platforms"][config]) return results @@ -189,10 +196,9 @@ class BuildOptions(NamedTuple): test_requires: List[str] test_extras: str build_verbosity: int - python_configs: List[Dict[str, str]] -resources_dir = Path(__file__).resolve().parent / 'resources' +resources_dir = files('cibuildwheel') / 'resources' get_pip_script = resources_dir / 'get-pip.py' install_certifi_script = resources_dir / "install_certifi.py" diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 96a80ffec..ef24fae96 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -22,6 +22,7 @@ get_build_verbosity_extra_flags, get_pip_script, prepare_command, + read_python_configs, ) IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists() @@ -56,12 +57,13 @@ class PythonConfiguration(NamedTuple): def get_python_configurations( - python_configs: List[Dict[str, str]], build_selector: BuildSelector, architectures: Set[Architecture], ) -> List[PythonConfiguration]: - python_configurations = [PythonConfiguration(**item) for item in python_configs] + full_python_configs = read_python_configs('windows') + + python_configurations = [PythonConfiguration(**item) for item in full_python_configs] map_arch = { '32': Architecture.x86, @@ -197,14 +199,14 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None: log.step('Performing PEP518 workaround...') with tempfile.TemporaryDirectory() as d: reqfile = Path(d) / "requirements.txt" - with reqfile.open("w") as f: + with reqfile.open('w') as f: for r in requirements: print(r, file=f) call(['pip', 'install', '-r', reqfile], env=env) def build(options: BuildOptions) -> None: - allowed_architectures_check("windows", options) + allowed_architectures_check('windows', options) temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel')) built_wheel_dir = temp_dir / 'built_wheel' @@ -217,7 +219,7 @@ def build(options: BuildOptions) -> None: before_all_prepared = prepare_command(options.before_all, project='.', package=options.package_dir) shell(before_all_prepared, env=env) - python_configurations = get_python_configurations(options.python_configs, options.build_selector, options.architectures) + python_configurations = get_python_configurations(options.build_selector, options.architectures) for config in python_configurations: log.build_start(config.identifier) diff --git a/setup.cfg b/setup.cfg index 2b23a5e90..0a6ac4b6e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ install_requires = toml certifi typing_extensions; python_version < '3.8' + importlib_resources; python_version < '3.9' [options.package_data] cibuildwheel = resources/* From 909007287a0fc3490af1d7e6528d14fde7d61f68 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Fri, 8 Jan 2021 23:39:30 -0500 Subject: [PATCH 5/8] refactor: change toml structure --- cibuildwheel/resources/build-platforms.toml | 12 ++++++++---- cibuildwheel/util.py | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cibuildwheel/resources/build-platforms.toml b/cibuildwheel/resources/build-platforms.toml index 2298e3f2d..e43bc1de1 100644 --- a/cibuildwheel/resources/build-platforms.toml +++ b/cibuildwheel/resources/build-platforms.toml @@ -1,5 +1,5 @@ -[tool.cibw.build-platforms] -linux = [ +[linux] +python_configurations = [ { identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27m" }, { identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27mu" }, { identifier = "cp35-manylinux_x86_64", version = "3.5", path_str = "/opt/python/cp35-cp35m" }, @@ -33,7 +33,9 @@ linux = [ { identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" }, { identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" }, ] -macos = [ + +[macos] +python_configurations = [ { identifier = "cp27-macosx_x86_64", version = "2.7", url = "https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg" }, { identifier = "cp35-macosx_x86_64", version = "3.5", url = "https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg" }, { identifier = "cp36-macosx_x86_64", version = "3.6", url = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg" }, @@ -44,7 +46,9 @@ macos = [ { identifier = "pp36-macosx_x86_64", version = "3.6", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2" }, { identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" }, ] -windows = [ + +[windows] +python_configurations = [ { identifier = "cp27-win32", version = "2.7.18", arch = "32" }, { identifier = "cp27-win_amd64", version = "2.7.18", arch = "64" }, { identifier = "cp35-win32", version = "3.5.4", arch = "32" }, diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index b80a12905..9614b5585 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -46,7 +46,7 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]: def read_python_configs(config: PlatformName) -> List[Dict[str, str]]: input_file = files('cibuildwheel') / 'resources/build-platforms.toml' loaded_file = toml.load(input_file) - results: List[Dict[str, str]] = list(loaded_file["tool"]["cibw"]["build-platforms"][config]) + results: List[Dict[str, str]] = list(loaded_file[config]['python_configurations']) return results From 67f59ddec9720fa4ef78bee1eb252061c231da91 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 9 Jan 2021 01:13:09 -0500 Subject: [PATCH 6/8] refactor: use common Traversable --- cibuildwheel/util.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index 9614b5585..a81d63067 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -24,6 +24,11 @@ from importlib.resources import files +resources_dir = files('cibuildwheel') / 'resources' +get_pip_script = resources_dir / 'get-pip.py' +install_certifi_script = resources_dir / "install_certifi.py" + + def prepare_command(command: str, **kwargs: PathOrStr) -> str: ''' Preprocesses a command by expanding variables like {python}. @@ -44,7 +49,7 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]: def read_python_configs(config: PlatformName) -> List[Dict[str, str]]: - input_file = files('cibuildwheel') / 'resources/build-platforms.toml' + input_file = resources_dir / 'build-platforms.toml' loaded_file = toml.load(input_file) results: List[Dict[str, str]] = list(loaded_file[config]['python_configurations']) return results @@ -198,10 +203,6 @@ class BuildOptions(NamedTuple): build_verbosity: int -resources_dir = files('cibuildwheel') / 'resources' -get_pip_script = resources_dir / 'get-pip.py' -install_certifi_script = resources_dir / "install_certifi.py" - class NonPlatformWheelError(Exception): def __init__(self) -> None: From 1d91408bb7d392721368bfaa88951879dcc92834 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 9 Jan 2021 01:23:17 -0500 Subject: [PATCH 7/8] fix: ensure reasonable version of importlib_resources --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 0a6ac4b6e..698935072 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,7 @@ install_requires = toml certifi typing_extensions; python_version < '3.8' - importlib_resources; python_version < '3.9' + importlib_resources>=1.4; python_version < '3.9' [options.package_data] cibuildwheel = resources/* From 46742454af54872541c4940930ec05d1f8360f9b Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 9 Jan 2021 01:26:25 -0500 Subject: [PATCH 8/8] style: fix extra line --- cibuildwheel/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index a81d63067..499b987df 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -203,7 +203,6 @@ class BuildOptions(NamedTuple): build_verbosity: int - class NonPlatformWheelError(Exception): def __init__(self) -> None: message = textwrap.dedent('''