feat: stricter selector parsing, refactor to platforms module (#2291)
* feat: stricter selector parsing, refactor to `platforms` module - Use a different method to build nothing - Make the check aware of enable groups * optimise unit tests - a specific platform module API for all configs Unit test time: 26.2s -> 13.1s * Remove unnecessary get_platform_module function
This commit is contained in:
+75
-43
@@ -9,25 +9,21 @@ import textwrap
|
||||
import time
|
||||
import traceback
|
||||
import typing
|
||||
from collections.abc import Generator, Iterable, Sequence, Set
|
||||
from collections.abc import Generator, Iterable, Sequence
|
||||
from pathlib import Path
|
||||
from tempfile import mkdtemp
|
||||
from typing import Any, Protocol, TextIO, assert_never
|
||||
from typing import Any, Literal, TextIO
|
||||
|
||||
import cibuildwheel
|
||||
import cibuildwheel.ios
|
||||
import cibuildwheel.linux
|
||||
import cibuildwheel.macos
|
||||
import cibuildwheel.pyodide
|
||||
import cibuildwheel.util
|
||||
import cibuildwheel.windows
|
||||
from cibuildwheel import errors
|
||||
from cibuildwheel.architecture import Architecture, allowed_architectures_check
|
||||
from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions
|
||||
from cibuildwheel.logger import log
|
||||
from cibuildwheel.options import CommandLineArguments, Options, compute_options
|
||||
from cibuildwheel.selector import BuildSelector, EnableGroup
|
||||
from cibuildwheel.typing import PLATFORMS, GenericPythonConfiguration, PlatformName
|
||||
from cibuildwheel.platforms import ALL_PLATFORM_MODULES, get_build_identifiers
|
||||
from cibuildwheel.selector import BuildSelector, EnableGroup, selector_matches
|
||||
from cibuildwheel.typing import PLATFORMS, PlatformName
|
||||
from cibuildwheel.util.file import CIBW_CACHE_PATH
|
||||
from cibuildwheel.util.helpers import strtobool
|
||||
|
||||
@@ -286,30 +282,6 @@ def _compute_platform(args: CommandLineArguments) -> PlatformName:
|
||||
return _compute_platform_auto()
|
||||
|
||||
|
||||
class PlatformModule(Protocol):
|
||||
# note that as per PEP544, the self argument is ignored when the protocol
|
||||
# is applied to a module
|
||||
def get_python_configurations(
|
||||
self, build_selector: BuildSelector, architectures: Set[Architecture]
|
||||
) -> Sequence[GenericPythonConfiguration]: ...
|
||||
|
||||
def build(self, options: Options, tmp_path: Path) -> None: ...
|
||||
|
||||
|
||||
def get_platform_module(platform: PlatformName) -> PlatformModule:
|
||||
if platform == "linux":
|
||||
return cibuildwheel.linux
|
||||
if platform == "windows":
|
||||
return cibuildwheel.windows
|
||||
if platform == "macos":
|
||||
return cibuildwheel.macos
|
||||
if platform == "pyodide":
|
||||
return cibuildwheel.pyodide
|
||||
if platform == "ios":
|
||||
return cibuildwheel.ios
|
||||
assert_never(platform)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def print_new_wheels(msg: str, output_dir: Path) -> Generator[None, None, None]:
|
||||
"""
|
||||
@@ -362,7 +334,7 @@ def build_in_directory(args: CommandLineArguments) -> None:
|
||||
msg = f"Could not find any of {{{names}}} at root of package"
|
||||
raise errors.ConfigurationError(msg)
|
||||
|
||||
platform_module = get_platform_module(platform)
|
||||
platform_module = ALL_PLATFORM_MODULES[platform]
|
||||
identifiers = get_build_identifiers(
|
||||
platform_module=platform_module,
|
||||
build_selector=options.globals.build_selector,
|
||||
@@ -448,15 +420,6 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
|
||||
print("Here we go!\n")
|
||||
|
||||
|
||||
def get_build_identifiers(
|
||||
platform_module: PlatformModule,
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture],
|
||||
) -> list[str]:
|
||||
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
|
||||
return [config.identifier for config in python_configurations]
|
||||
|
||||
|
||||
def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str]:
|
||||
warnings = []
|
||||
|
||||
@@ -482,6 +445,75 @@ def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str
|
||||
)
|
||||
raise errors.ConfigurationError(msg)
|
||||
|
||||
build_selector = options.globals.build_selector
|
||||
test_selector = options.globals.test_selector
|
||||
|
||||
all_valid_identifiers = [
|
||||
config.identifier
|
||||
for module in ALL_PLATFORM_MODULES.values()
|
||||
for config in module.all_python_configurations()
|
||||
]
|
||||
|
||||
enabled_selector = BuildSelector(
|
||||
build_config="*", skip_config="", enable=options.globals.build_selector.enable
|
||||
)
|
||||
all_enabled_identifiers = [
|
||||
identifier for identifier in all_valid_identifiers if enabled_selector(identifier)
|
||||
]
|
||||
|
||||
warnings += check_for_invalid_selectors(
|
||||
selector_name="build",
|
||||
selector_value=build_selector.build_config,
|
||||
all_valid_identifiers=all_valid_identifiers,
|
||||
all_enabled_identifiers=all_enabled_identifiers,
|
||||
)
|
||||
warnings += check_for_invalid_selectors(
|
||||
selector_name="skip",
|
||||
selector_value=build_selector.skip_config,
|
||||
all_valid_identifiers=all_valid_identifiers,
|
||||
all_enabled_identifiers=all_enabled_identifiers,
|
||||
)
|
||||
warnings += check_for_invalid_selectors(
|
||||
selector_name="test_skip",
|
||||
selector_value=test_selector.skip_config,
|
||||
all_valid_identifiers=all_valid_identifiers,
|
||||
all_enabled_identifiers=all_enabled_identifiers,
|
||||
)
|
||||
|
||||
return warnings
|
||||
|
||||
|
||||
def check_for_invalid_selectors(
|
||||
*,
|
||||
selector_name: Literal["build", "skip", "test_skip"],
|
||||
selector_value: str,
|
||||
all_valid_identifiers: Sequence[str],
|
||||
all_enabled_identifiers: Sequence[str],
|
||||
) -> list[str]:
|
||||
warnings = []
|
||||
|
||||
for selector in selector_value.split():
|
||||
if not any(selector_matches(selector, i) for i in all_enabled_identifiers):
|
||||
msg = f"Invalid {selector_name} selector: {selector!r}. "
|
||||
error_type: type = errors.ConfigurationError
|
||||
|
||||
if any(selector_matches(selector, i) for i in all_valid_identifiers):
|
||||
msg += "This selector matches a group that wasn't enabled. Enable it using the `enable` option or remove this selector. "
|
||||
|
||||
if "p2" in selector or "p35" in selector:
|
||||
msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update `{selector_name}`. "
|
||||
error_type = errors.DeprecationError
|
||||
if "p36" in selector or "p37" in selector:
|
||||
msg += f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `{selector_name}`. "
|
||||
error_type = errors.DeprecationError
|
||||
|
||||
if selector_name == "build":
|
||||
raise error_type(msg)
|
||||
|
||||
msg += "This selector will have no effect. "
|
||||
|
||||
warnings.append(msg)
|
||||
|
||||
return warnings
|
||||
|
||||
|
||||
|
||||
+1
-24
@@ -863,14 +863,6 @@ class Options:
|
||||
)
|
||||
)
|
||||
|
||||
def check_for_deprecated_options(self) -> None:
|
||||
build_selector = self.globals.build_selector
|
||||
test_selector = self.globals.test_selector
|
||||
|
||||
deprecated_selectors("CIBW_BUILD", build_selector.build_config, error=True)
|
||||
deprecated_selectors("CIBW_SKIP", build_selector.skip_config)
|
||||
deprecated_selectors("CIBW_TEST_SKIP", test_selector.skip_config)
|
||||
|
||||
@functools.cached_property
|
||||
def defaults(self) -> Self:
|
||||
return self.__class__(
|
||||
@@ -985,9 +977,7 @@ def compute_options(
|
||||
command_line_arguments: CommandLineArguments,
|
||||
env: Mapping[str, str],
|
||||
) -> Options:
|
||||
options = Options(platform=platform, command_line_arguments=command_line_arguments, env=env)
|
||||
options.check_for_deprecated_options()
|
||||
return options
|
||||
return Options(platform=platform, command_line_arguments=command_line_arguments, env=env)
|
||||
|
||||
|
||||
@functools.cache
|
||||
@@ -1002,16 +992,3 @@ def _get_pinned_container_images() -> Mapping[str, Mapping[str, str]]:
|
||||
all_pinned_images = configparser.ConfigParser()
|
||||
all_pinned_images.read(resources.PINNED_DOCKER_IMAGES)
|
||||
return all_pinned_images
|
||||
|
||||
|
||||
def deprecated_selectors(name: str, selector: str, *, error: bool = False) -> None:
|
||||
if "p2" in selector or "p35" in selector:
|
||||
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update {name}"
|
||||
if error:
|
||||
raise errors.DeprecationError(msg)
|
||||
log.warning(msg)
|
||||
if "p36" in selector or "p37" in selector:
|
||||
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update {name}"
|
||||
if error:
|
||||
raise errors.DeprecationError(msg)
|
||||
log.warning(msg)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
from typing import Final, Protocol
|
||||
|
||||
from cibuildwheel.architecture import Architecture
|
||||
from cibuildwheel.options import Options
|
||||
from cibuildwheel.platforms import ios, linux, macos, pyodide, windows
|
||||
from cibuildwheel.selector import BuildSelector
|
||||
from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
|
||||
|
||||
|
||||
class PlatformModule(Protocol):
|
||||
# note that as per PEP544, the self argument is ignored when the protocol
|
||||
# is applied to a module
|
||||
def all_python_configurations(self) -> Sequence[GenericPythonConfiguration]: ...
|
||||
|
||||
def get_python_configurations(
|
||||
self, build_selector: BuildSelector, architectures: set[Architecture]
|
||||
) -> Sequence[GenericPythonConfiguration]: ...
|
||||
|
||||
def build(self, options: Options, tmp_path: Path) -> None: ...
|
||||
|
||||
|
||||
ALL_PLATFORM_MODULES: Final[dict[PlatformName, PlatformModule]] = {
|
||||
"linux": linux,
|
||||
"windows": windows,
|
||||
"macos": macos,
|
||||
"pyodide": pyodide,
|
||||
"ios": ios,
|
||||
}
|
||||
|
||||
|
||||
def get_build_identifiers(
|
||||
platform_module: PlatformModule,
|
||||
build_selector: BuildSelector,
|
||||
architectures: set[Architecture],
|
||||
) -> list[str]:
|
||||
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
|
||||
return [config.identifier for config in python_configurations]
|
||||
@@ -12,34 +12,34 @@ from typing import assert_never
|
||||
|
||||
from filelock import FileLock
|
||||
|
||||
from . import errors
|
||||
from .architecture import Architecture
|
||||
from .environment import ParsedEnvironment
|
||||
from .frontend import (
|
||||
from .. import errors
|
||||
from ..architecture import Architecture
|
||||
from ..environment import ParsedEnvironment
|
||||
from ..frontend import (
|
||||
BuildFrontendConfig,
|
||||
BuildFrontendName,
|
||||
get_build_frontend_extra_flags,
|
||||
)
|
||||
from .logger import log
|
||||
from .macos import install_cpython as install_build_cpython
|
||||
from .options import Options
|
||||
from .selector import BuildSelector
|
||||
from .typing import PathOrStr
|
||||
from .util import resources
|
||||
from .util.cmd import call, shell
|
||||
from .util.file import (
|
||||
from ..logger import log
|
||||
from ..options import Options
|
||||
from ..selector import BuildSelector
|
||||
from ..typing import PathOrStr
|
||||
from ..util import resources
|
||||
from ..util.cmd import call, shell
|
||||
from ..util.file import (
|
||||
CIBW_CACHE_PATH,
|
||||
copy_test_sources,
|
||||
download,
|
||||
move_file,
|
||||
)
|
||||
from .util.helpers import prepare_command
|
||||
from .util.packaging import (
|
||||
from ..util.helpers import prepare_command
|
||||
from ..util.packaging import (
|
||||
combine_constraints,
|
||||
find_compatible_wheel,
|
||||
get_pip_version,
|
||||
)
|
||||
from .venv import virtualenv
|
||||
from ..venv import virtualenv
|
||||
from .macos import install_cpython as install_build_cpython
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -72,10 +72,7 @@ class PythonConfiguration:
|
||||
return "ios-arm64_x86_64-simulator" if self.is_simulator else "ios-arm64"
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture],
|
||||
) -> list[PythonConfiguration]:
|
||||
def all_python_configurations() -> list[PythonConfiguration]:
|
||||
# iOS builds are always cross builds; we need to install a macOS Python as
|
||||
# well. Rather than duplicate the location of the URL of macOS installers,
|
||||
# load the macos configurations, determine the macOS configuration that
|
||||
@@ -97,7 +94,7 @@ def get_python_configurations(
|
||||
# Load the platform configuration
|
||||
full_python_configs = resources.read_python_configs("ios")
|
||||
# Build the configurations, annotating with macOS URL details.
|
||||
python_configurations = [
|
||||
return [
|
||||
PythonConfiguration(
|
||||
**item,
|
||||
build_url=build_url(item),
|
||||
@@ -105,6 +102,13 @@ def get_python_configurations(
|
||||
for item in full_python_configs
|
||||
]
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture],
|
||||
) -> list[PythonConfiguration]:
|
||||
python_configurations = all_python_configurations()
|
||||
|
||||
# Filter out configs that don't match any of the selected architectures
|
||||
python_configurations = [
|
||||
c
|
||||
@@ -8,18 +8,18 @@ from dataclasses import dataclass
|
||||
from pathlib import Path, PurePath, PurePosixPath
|
||||
from typing import assert_never
|
||||
|
||||
from . import errors
|
||||
from .architecture import Architecture
|
||||
from .frontend import BuildFrontendConfig, get_build_frontend_extra_flags
|
||||
from .logger import log
|
||||
from .oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
|
||||
from .options import BuildOptions, Options
|
||||
from .selector import BuildSelector
|
||||
from .typing import PathOrStr
|
||||
from .util import resources
|
||||
from .util.file import copy_test_sources
|
||||
from .util.helpers import prepare_command, unwrap
|
||||
from .util.packaging import find_compatible_wheel
|
||||
from .. import errors
|
||||
from ..architecture import Architecture
|
||||
from ..frontend import BuildFrontendConfig, get_build_frontend_extra_flags
|
||||
from ..logger import log
|
||||
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
|
||||
from ..options import BuildOptions, Options
|
||||
from ..selector import BuildSelector
|
||||
from ..typing import PathOrStr
|
||||
from ..util import resources
|
||||
from ..util.file import copy_test_sources
|
||||
from ..util.helpers import prepare_command, unwrap
|
||||
from ..util.packaging import find_compatible_wheel
|
||||
|
||||
ARCHITECTURE_OCI_PLATFORM_MAP = {
|
||||
Architecture.x86_64: OCIPlatform.AMD64,
|
||||
@@ -50,13 +50,16 @@ class BuildStep:
|
||||
container_image: str
|
||||
|
||||
|
||||
def all_python_configurations() -> list[PythonConfiguration]:
|
||||
config_dicts = resources.read_python_configs("linux")
|
||||
return [PythonConfiguration(**item) for item in config_dicts]
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture],
|
||||
) -> list[PythonConfiguration]:
|
||||
full_python_configs = resources.read_python_configs("linux")
|
||||
|
||||
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
|
||||
python_configurations = all_python_configurations()
|
||||
|
||||
# return all configurations whose arch is in our `architectures` set,
|
||||
# and match the build/skip rules
|
||||
@@ -15,26 +15,26 @@ from typing import Literal, assert_never
|
||||
from filelock import FileLock
|
||||
from packaging.version import Version
|
||||
|
||||
from . import errors
|
||||
from .architecture import Architecture
|
||||
from .ci import detect_ci_provider
|
||||
from .environment import ParsedEnvironment
|
||||
from .frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
|
||||
from .logger import log
|
||||
from .options import Options
|
||||
from .selector import BuildSelector
|
||||
from .typing import PathOrStr
|
||||
from .util import resources
|
||||
from .util.cmd import call, shell
|
||||
from .util.file import (
|
||||
from .. import errors
|
||||
from ..architecture import Architecture
|
||||
from ..ci import detect_ci_provider
|
||||
from ..environment import ParsedEnvironment
|
||||
from ..frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
|
||||
from ..logger import log
|
||||
from ..options import Options
|
||||
from ..selector import BuildSelector
|
||||
from ..typing import PathOrStr
|
||||
from ..util import resources
|
||||
from ..util.cmd import call, shell
|
||||
from ..util.file import (
|
||||
CIBW_CACHE_PATH,
|
||||
copy_test_sources,
|
||||
download,
|
||||
move_file,
|
||||
)
|
||||
from .util.helpers import prepare_command, unwrap
|
||||
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from .venv import find_uv, virtualenv
|
||||
from ..util.helpers import prepare_command, unwrap
|
||||
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from ..venv import find_uv, virtualenv
|
||||
|
||||
|
||||
@functools.cache
|
||||
@@ -84,12 +84,15 @@ class PythonConfiguration:
|
||||
url: str
|
||||
|
||||
|
||||
def all_python_configurations() -> list[PythonConfiguration]:
|
||||
config_dicts = resources.read_python_configs("macos")
|
||||
return [PythonConfiguration(**item) for item in config_dicts]
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector, architectures: Set[Architecture]
|
||||
) -> list[PythonConfiguration]:
|
||||
full_python_configs = resources.read_python_configs("macos")
|
||||
|
||||
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
|
||||
python_configurations = all_python_configurations()
|
||||
|
||||
# filter out configs that don't match any of the selected architectures
|
||||
python_configurations = [
|
||||
@@ -11,17 +11,17 @@ from typing import Final
|
||||
|
||||
from filelock import FileLock
|
||||
|
||||
from . import errors
|
||||
from .architecture import Architecture
|
||||
from .environment import ParsedEnvironment
|
||||
from .frontend import BuildFrontendConfig, get_build_frontend_extra_flags
|
||||
from .logger import log
|
||||
from .options import Options
|
||||
from .selector import BuildSelector
|
||||
from .typing import PathOrStr
|
||||
from .util import resources
|
||||
from .util.cmd import call, shell
|
||||
from .util.file import (
|
||||
from .. import errors
|
||||
from ..architecture import Architecture
|
||||
from ..environment import ParsedEnvironment
|
||||
from ..frontend import BuildFrontendConfig, get_build_frontend_extra_flags
|
||||
from ..logger import log
|
||||
from ..options import Options
|
||||
from ..selector import BuildSelector
|
||||
from ..typing import PathOrStr
|
||||
from ..util import resources
|
||||
from ..util.cmd import call, shell
|
||||
from ..util.file import (
|
||||
CIBW_CACHE_PATH,
|
||||
copy_test_sources,
|
||||
download,
|
||||
@@ -29,9 +29,9 @@ from .util.file import (
|
||||
extract_zip,
|
||||
move_file,
|
||||
)
|
||||
from .util.helpers import prepare_command
|
||||
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from .venv import virtualenv
|
||||
from ..util.helpers import prepare_command
|
||||
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from ..venv import virtualenv
|
||||
|
||||
IS_WIN: Final[bool] = sys.platform.startswith("win")
|
||||
|
||||
@@ -215,15 +215,16 @@ def setup_python(
|
||||
return env
|
||||
|
||||
|
||||
def all_python_configurations() -> list[PythonConfiguration]:
|
||||
full_python_configs = resources.read_python_configs("pyodide")
|
||||
return [PythonConfiguration(**item) for item in full_python_configs]
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture], # noqa: ARG001
|
||||
) -> list[PythonConfiguration]:
|
||||
full_python_configs = resources.read_python_configs("pyodide")
|
||||
|
||||
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
|
||||
python_configurations = [c for c in python_configurations if build_selector(c.identifier)]
|
||||
return python_configurations
|
||||
return [c for c in all_python_configurations() if build_selector(c.identifier)]
|
||||
|
||||
|
||||
def build(options: Options, tmp_path: Path) -> None:
|
||||
@@ -11,20 +11,20 @@ from typing import assert_never
|
||||
|
||||
from filelock import FileLock
|
||||
|
||||
from . import errors
|
||||
from .architecture import Architecture
|
||||
from .environment import ParsedEnvironment
|
||||
from .frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
|
||||
from .logger import log
|
||||
from .options import Options
|
||||
from .selector import BuildSelector
|
||||
from .typing import PathOrStr
|
||||
from .util import resources
|
||||
from .util.cmd import call, shell
|
||||
from .util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
|
||||
from .util.helpers import prepare_command, unwrap
|
||||
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from .venv import find_uv, virtualenv
|
||||
from .. import errors
|
||||
from ..architecture import Architecture
|
||||
from ..environment import ParsedEnvironment
|
||||
from ..frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
|
||||
from ..logger import log
|
||||
from ..options import Options
|
||||
from ..selector import BuildSelector
|
||||
from ..typing import PathOrStr
|
||||
from ..util import resources
|
||||
from ..util.cmd import call, shell
|
||||
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
|
||||
from ..util.helpers import prepare_command, unwrap
|
||||
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
|
||||
from ..venv import find_uv, virtualenv
|
||||
|
||||
|
||||
def get_nuget_args(
|
||||
@@ -59,13 +59,16 @@ class PythonConfiguration:
|
||||
url: str | None = None
|
||||
|
||||
|
||||
def all_python_configurations() -> list[PythonConfiguration]:
|
||||
config_dicts = resources.read_python_configs("windows")
|
||||
return [PythonConfiguration(**item) for item in config_dicts]
|
||||
|
||||
|
||||
def get_python_configurations(
|
||||
build_selector: BuildSelector,
|
||||
architectures: Set[Architecture],
|
||||
) -> list[PythonConfiguration]:
|
||||
full_python_configs = resources.read_python_configs("windows")
|
||||
|
||||
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
|
||||
python_configurations = all_python_configurations()
|
||||
|
||||
map_arch = {"32": Architecture.x86, "64": Architecture.AMD64, "ARM64": Architecture.ARM64}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import itertools
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from enum import StrEnum
|
||||
from fnmatch import fnmatch
|
||||
from typing import Any
|
||||
|
||||
@@ -24,7 +24,7 @@ def selector_matches(patterns: str, string: str) -> bool:
|
||||
return any(fnmatch(string, pat) for pat in expanded_patterns)
|
||||
|
||||
|
||||
class EnableGroup(Enum):
|
||||
class EnableGroup(StrEnum):
|
||||
"""
|
||||
Groups of build selectors that are not enabled by default.
|
||||
"""
|
||||
@@ -33,6 +33,10 @@ class EnableGroup(Enum):
|
||||
CPythonPrerelease = "cpython-prerelease"
|
||||
PyPy = "pypy"
|
||||
|
||||
@classmethod
|
||||
def all_groups(cls) -> frozenset["EnableGroup"]:
|
||||
return frozenset(cls)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class BuildSelector:
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_allow_empty(tmp_path, add_args, env_allow_empty):
|
||||
# without error
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={"CIBW_BUILD": "BUILD_NOTHING_AT_ALL", **env_allow_empty},
|
||||
add_env={"CIBW_SKIP": "*", **env_allow_empty},
|
||||
add_args=add_args,
|
||||
)
|
||||
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ import pytest
|
||||
|
||||
from cibuildwheel.architecture import Architecture
|
||||
from cibuildwheel.ci import CIProvider, detect_ci_provider
|
||||
from cibuildwheel.selector import EnableGroup
|
||||
from cibuildwheel.util.file import CIBW_CACHE_PATH
|
||||
|
||||
EMULATED_ARCHS: Final[list[str]] = sorted(
|
||||
@@ -120,7 +121,7 @@ def cibuildwheel_run(
|
||||
|
||||
_update_pip_cache_dir(env)
|
||||
|
||||
env["CIBW_ENABLE"] = "cpython-prerelease cpython-freethreading pypy"
|
||||
env["CIBW_ENABLE"] = " ".join(EnableGroup.all_groups())
|
||||
|
||||
if single_python:
|
||||
env["CIBW_BUILD"] = "cp{}{}-*".format(*SINGLE_PYTHON_VERSION)
|
||||
|
||||
@@ -7,7 +7,7 @@ import setuptools._distutils.util
|
||||
|
||||
from cibuildwheel.ci import CIProvider, detect_ci_provider
|
||||
from cibuildwheel.errors import FatalError
|
||||
from cibuildwheel.windows import PythonConfiguration, setup_setuptools_cross_compile
|
||||
from cibuildwheel.platforms.windows import PythonConfiguration, setup_setuptools_cross_compile
|
||||
|
||||
# monkeypatching os.name is too flaky. E.g. It works on my machine, but fails in pipeline
|
||||
if not sys.platform.startswith("win"):
|
||||
|
||||
@@ -4,7 +4,7 @@ from pprint import pprint
|
||||
|
||||
import pytest
|
||||
|
||||
import cibuildwheel.linux
|
||||
import cibuildwheel.platforms.linux
|
||||
from cibuildwheel.oci_container import OCIContainerEngineConfig
|
||||
from cibuildwheel.options import CommandLineArguments, Options
|
||||
|
||||
@@ -46,20 +46,22 @@ def test_linux_container_split(tmp_path: Path, monkeypatch: pytest.MonkeyPatch)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
options = Options("linux", command_line_arguments=args, env={})
|
||||
|
||||
python_configurations = cibuildwheel.linux.get_python_configurations(
|
||||
python_configurations = cibuildwheel.platforms.linux.get_python_configurations(
|
||||
options.globals.build_selector, options.globals.architectures
|
||||
)
|
||||
|
||||
build_steps = list(cibuildwheel.linux.get_build_steps(options, python_configurations))
|
||||
build_steps = list(cibuildwheel.platforms.linux.get_build_steps(options, python_configurations))
|
||||
|
||||
# helper functions to extract test info
|
||||
def identifiers(step: cibuildwheel.linux.BuildStep) -> list[str]:
|
||||
def identifiers(step: cibuildwheel.platforms.linux.BuildStep) -> list[str]:
|
||||
return [c.identifier for c in step.platform_configs]
|
||||
|
||||
def before_alls(step: cibuildwheel.linux.BuildStep) -> list[str]:
|
||||
def before_alls(step: cibuildwheel.platforms.linux.BuildStep) -> list[str]:
|
||||
return [options.build_options(c.identifier).before_all for c in step.platform_configs]
|
||||
|
||||
def container_engines(step: cibuildwheel.linux.BuildStep) -> list[OCIContainerEngineConfig]:
|
||||
def container_engines(
|
||||
step: cibuildwheel.platforms.linux.BuildStep,
|
||||
) -> list[OCIContainerEngineConfig]:
|
||||
return [options.build_options(c.identifier).container_engine for c in step.platform_configs]
|
||||
|
||||
pprint(build_steps)
|
||||
|
||||
@@ -6,7 +6,8 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel import __main__, architecture, linux, macos, pyodide, windows
|
||||
from cibuildwheel import __main__, architecture
|
||||
from cibuildwheel.platforms import linux, macos, pyodide, windows
|
||||
from cibuildwheel.util import file
|
||||
|
||||
|
||||
|
||||
@@ -50,22 +50,49 @@ def test_output_dir_argument(also_set_environment, intercepted_build_args, monke
|
||||
|
||||
@pytest.mark.usefixtures("platform", "allow_empty")
|
||||
def test_build_selector(intercepted_build_args, monkeypatch):
|
||||
BUILD = "some build* *-selector"
|
||||
SKIP = "some skip* *-selector"
|
||||
|
||||
monkeypatch.setenv("CIBW_BUILD", BUILD)
|
||||
monkeypatch.setenv("CIBW_SKIP", SKIP)
|
||||
monkeypatch.setenv("CIBW_BUILD", "cp313-*")
|
||||
monkeypatch.setenv("CIBW_SKIP", "cp39-*")
|
||||
|
||||
main()
|
||||
|
||||
intercepted_build_selector = intercepted_build_args.args[0].globals.build_selector
|
||||
assert isinstance(intercepted_build_selector, BuildSelector)
|
||||
assert intercepted_build_selector("build24-this")
|
||||
assert not intercepted_build_selector("skip65-that")
|
||||
assert intercepted_build_selector("cp313-something-to-build")
|
||||
assert not intercepted_build_selector("cp39-something-to-skip")
|
||||
# This unit test is just testing the options of 'main'
|
||||
# Unit tests for BuildSelector are in build_selector_test.py
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("platform", "allow_empty")
|
||||
def test_invalid_build_selector(monkeypatch, capsys):
|
||||
monkeypatch.setenv("CIBW_BUILD", "invalid")
|
||||
|
||||
with pytest.raises(SystemExit) as e:
|
||||
main()
|
||||
|
||||
assert e.value.code == 2
|
||||
_, err = capsys.readouterr()
|
||||
assert "Invalid build selector" in err
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("option_name", "option_env_var"),
|
||||
[
|
||||
("skip", "CIBW_SKIP"),
|
||||
("test_skip", "CIBW_TEST_SKIP"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("platform", "intercepted_build_args")
|
||||
def test_invalid_skip_selector(monkeypatch, capsys, option_name, option_env_var):
|
||||
monkeypatch.setenv(option_env_var, "invalid")
|
||||
|
||||
main()
|
||||
|
||||
_, err = capsys.readouterr()
|
||||
print(err)
|
||||
assert f"Invalid {option_name} selector" in err
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("platform", "intercepted_build_args")
|
||||
def test_empty_selector(monkeypatch):
|
||||
monkeypatch.setenv("CIBW_SKIP", "*")
|
||||
@@ -313,7 +340,7 @@ def test_build_selector_deprecated_error(monkeypatch, selector, pattern, capsys)
|
||||
|
||||
stderr = capsys.readouterr().err
|
||||
series = "2" if "6" in pattern else "1"
|
||||
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the {series}.x series or update {selector}"
|
||||
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the {series}.x series or update"
|
||||
assert msg in stderr
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel import linux
|
||||
from cibuildwheel import platforms
|
||||
from cibuildwheel.__main__ import main
|
||||
from cibuildwheel.oci_container import OCIPlatform
|
||||
from cibuildwheel.util import file
|
||||
@@ -39,10 +39,11 @@ def mock_build_container(monkeypatch):
|
||||
monkeypatch.setattr(subprocess, "Popen", fail_on_call)
|
||||
monkeypatch.setattr(subprocess, "run", ignore_call)
|
||||
monkeypatch.setattr(file, "download", fail_on_call)
|
||||
monkeypatch.setattr("cibuildwheel.linux.OCIContainer", ignore_context_call)
|
||||
monkeypatch.setattr("cibuildwheel.platforms.linux.OCIContainer", ignore_context_call)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"cibuildwheel.linux.build_in_container", mock.Mock(spec=linux.build_in_container)
|
||||
"cibuildwheel.platforms.linux.build_in_container",
|
||||
mock.Mock(spec=platforms.linux.build_in_container),
|
||||
)
|
||||
monkeypatch.setattr("cibuildwheel.__main__.print_new_wheels", ignore_context_call)
|
||||
|
||||
@@ -53,7 +54,7 @@ def test_build_default_launches(monkeypatch):
|
||||
|
||||
main()
|
||||
|
||||
build_in_container = typing.cast(mock.Mock, linux.build_in_container)
|
||||
build_in_container = typing.cast(mock.Mock, platforms.linux.build_in_container)
|
||||
|
||||
assert build_in_container.call_count == 4
|
||||
|
||||
@@ -121,7 +122,7 @@ before-all = "true"
|
||||
|
||||
main()
|
||||
|
||||
build_in_container = typing.cast(mock.Mock, linux.build_in_container)
|
||||
build_in_container = typing.cast(mock.Mock, platforms.linux.build_in_container)
|
||||
|
||||
assert build_in_container.call_count == 6
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from cibuildwheel import errors
|
||||
from cibuildwheel.__main__ import get_build_identifiers, get_platform_module
|
||||
from cibuildwheel.bashlex_eval import local_environment_executor
|
||||
from cibuildwheel.options import (
|
||||
CommandLineArguments,
|
||||
Options,
|
||||
_get_pinned_container_images,
|
||||
)
|
||||
from cibuildwheel.platforms import ALL_PLATFORM_MODULES, get_build_identifiers
|
||||
from cibuildwheel.selector import EnableGroup
|
||||
from cibuildwheel.util import resources
|
||||
from cibuildwheel.util.packaging import DependencyConstraints
|
||||
@@ -51,7 +51,7 @@ def test_options_1(tmp_path, monkeypatch):
|
||||
|
||||
options = Options(platform="linux", command_line_arguments=args, env={})
|
||||
|
||||
module = get_platform_module("linux")
|
||||
module = ALL_PLATFORM_MODULES["linux"]
|
||||
identifiers = get_build_identifiers(
|
||||
platform_module=module,
|
||||
build_selector=options.globals.build_selector,
|
||||
|
||||
Reference in New Issue
Block a user