From 26dd3f399e67d4ef4d4eb17f9f0030dd632406a4 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Fri, 7 Apr 2023 13:51:38 -0700 Subject: [PATCH] chore: Add a platform_interface type to export from each platform This avoids the repetition of the platform checks in __main__.py by defining a dataclass with `get_python_configurations` and `build`. --- cibuildwheel/__main__.py | 46 +++++++++++------------------- cibuildwheel/linux.py | 4 +++ cibuildwheel/macos.py | 4 +++ cibuildwheel/platform_interface.py | 19 ++++++++++++ cibuildwheel/windows.py | 4 +++ unit_test/main_tests/conftest.py | 6 ++-- unit_test/options_test.py | 5 ++-- 7 files changed, 54 insertions(+), 34 deletions(-) create mode 100644 cibuildwheel/platform_interface.py diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 7ae2057f..061439b1 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -7,7 +7,7 @@ import sys import tarfile import textwrap import typing -from collections.abc import Sequence, Set +from collections.abc import Set from pathlib import Path from tempfile import mkdtemp @@ -19,9 +19,9 @@ import cibuildwheel.windows from cibuildwheel.architecture import Architecture, allowed_architectures_check from cibuildwheel.logger import log from cibuildwheel.options import CommandLineArguments, Options, compute_options +from cibuildwheel.platform_interface import PlatformInterface from cibuildwheel.typing import ( PLATFORMS, - GenericPythonConfiguration, PlatformName, assert_never, ) @@ -244,6 +244,16 @@ def _compute_platform(args: CommandLineArguments) -> PlatformName: return _compute_platform_ci() +def get_platform_interface(platform: PlatformName) -> PlatformInterface: + if platform == "linux": # noqa: SIM116 + return cibuildwheel.linux.interface + elif platform == "windows": + return cibuildwheel.windows.interface + elif platform == "macos": + return cibuildwheel.macos.interface + assert_never(platform) + + def build_in_directory(args: CommandLineArguments) -> None: platform: PlatformName = _compute_platform(args) options = compute_options(platform=platform, command_line_arguments=args, env=os.environ) @@ -257,8 +267,9 @@ def build_in_directory(args: CommandLineArguments) -> None: print(msg, file=sys.stderr) sys.exit(2) + interface = get_platform_interface(platform) identifiers = get_build_identifiers( - platform=platform, + interface=interface, build_selector=options.globals.build_selector, architectures=options.globals.architectures, ) @@ -304,14 +315,7 @@ def build_in_directory(args: CommandLineArguments) -> None: with cibuildwheel.util.print_new_wheels( "\n{n} wheels produced in {m:.0f} minutes:", output_dir ): - if platform == "linux": - cibuildwheel.linux.build(options, tmp_path) - elif platform == "windows": - cibuildwheel.windows.build(options, tmp_path) - elif platform == "macos": - cibuildwheel.macos.build(options, tmp_path) - else: - assert_never(platform) + interface.build(options, tmp_path) finally: # avoid https://github.com/python/cpython/issues/86962 by performing # cleanup manually @@ -354,25 +358,9 @@ def print_preamble(platform: str, options: Options, identifiers: list[str]) -> N def get_build_identifiers( - platform: PlatformName, build_selector: BuildSelector, architectures: Set[Architecture] + interface: PlatformInterface, build_selector: BuildSelector, architectures: Set[Architecture] ) -> list[str]: - python_configurations: Sequence[GenericPythonConfiguration] - - if platform == "linux": - python_configurations = cibuildwheel.linux.get_python_configurations( - build_selector, architectures - ) - elif platform == "windows": - python_configurations = cibuildwheel.windows.get_python_configurations( - build_selector, architectures - ) - elif platform == "macos": - python_configurations = cibuildwheel.macos.get_python_configurations( - build_selector, architectures - ) - else: - assert_never(platform) - + python_configurations = interface.get_python_configurations(build_selector, architectures) return [config.identifier for config in python_configurations] diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 1a1f7103..bd237600 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -12,6 +12,7 @@ from .architecture import Architecture from .logger import log from .oci_container import OCIContainer from .options import Options +from .platform_interface import PlatformInterface from .typing import OrderedDict, PathOrStr, assert_never from .util import ( AlreadyBuiltWheelError, @@ -483,3 +484,6 @@ def troubleshoot(options: Options, error: Exception) -> None: print(" Files detected:") print("\n".join(f" {f}" for f in so_files)) print() + + +interface = PlatformInterface(get_python_configurations=get_python_configurations, build=build) diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 6047b1ee..6b1d1aca 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -19,6 +19,7 @@ from .architecture import Architecture from .environment import ParsedEnvironment from .logger import log from .options import Options +from .platform_interface import PlatformInterface from .typing import Literal, PathOrStr, assert_never from .util import ( CIBW_CACHE_PATH, @@ -622,3 +623,6 @@ def build(options: Options, tmp_path: Path) -> None: f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}" ) sys.exit(1) + + +interface = PlatformInterface(get_python_configurations=get_python_configurations, build=build) diff --git a/cibuildwheel/platform_interface.py b/cibuildwheel/platform_interface.py new file mode 100644 index 00000000..c1bf8819 --- /dev/null +++ b/cibuildwheel/platform_interface.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import dataclasses +from collections.abc import Callable, Sequence, Set +from pathlib import Path + +from .architecture import Architecture +from .options import Options +from .typing import GenericPythonConfiguration +from .util import BuildSelector + + +# Can't make it frozen because we monkeypatch "build" in unit tests +@dataclasses.dataclass() +class PlatformInterface: + get_python_configurations: Callable[ + [BuildSelector, Set[Architecture]], Sequence[GenericPythonConfiguration] + ] + build: Callable[[Options, Path], None] diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index e0f16d81..7cbf76eb 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -20,6 +20,7 @@ from .architecture import Architecture from .environment import ParsedEnvironment from .logger import log from .options import Options +from .platform_interface import PlatformInterface from .typing import PathOrStr, assert_never from .util import ( CIBW_CACHE_PATH, @@ -574,3 +575,6 @@ def build(options: Options, tmp_path: Path) -> None: f"Command {error.cmd} failed with code {error.returncode}. {error.stdout}" ) sys.exit(1) + + +interface = PlatformInterface(get_python_configurations=get_python_configurations, build=build) diff --git a/unit_test/main_tests/conftest.py b/unit_test/main_tests/conftest.py index 9ca5fa52..d9401628 100644 --- a/unit_test/main_tests/conftest.py +++ b/unit_test/main_tests/conftest.py @@ -85,9 +85,9 @@ def platform(request, monkeypatch): def intercepted_build_args(monkeypatch): intercepted = ArgsInterceptor() - monkeypatch.setattr(linux, "build", intercepted) - monkeypatch.setattr(macos, "build", intercepted) - monkeypatch.setattr(windows, "build", intercepted) + monkeypatch.setattr(linux.interface, "build", intercepted) + monkeypatch.setattr(macos.interface, "build", intercepted) + monkeypatch.setattr(windows.interface, "build", intercepted) yield intercepted diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 5a29c91b..5463a3b6 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -7,7 +7,7 @@ from pathlib import Path import pytest -from cibuildwheel.__main__ import get_build_identifiers +from cibuildwheel.__main__ import get_build_identifiers, get_platform_interface from cibuildwheel.bashlex_eval import local_environment_executor from cibuildwheel.environment import parse_environment from cibuildwheel.options import ( @@ -49,8 +49,9 @@ def test_options_1(tmp_path, monkeypatch): options = Options(platform="linux", command_line_arguments=args, env={}) + interface = get_platform_interface("linux") identifiers = get_build_identifiers( - platform="linux", + interface=interface, build_selector=options.globals.build_selector, architectures=options.globals.architectures, )