Skip to content

Commit fe78ba6

Browse files
committed
feat: stricter selector parsing, refactor to platforms module
1 parent 88ef8db commit fe78ba6

13 files changed

+206
-140
lines changed

cibuildwheel/__main__.py

+47-39
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,21 @@
1111
import time
1212
import traceback
1313
import typing
14-
from collections.abc import Generator, Iterable, Sequence, Set
14+
from collections.abc import Generator, Iterable, Sequence
1515
from pathlib import Path
1616
from tempfile import mkdtemp
17-
from typing import Any, Protocol, TextIO, assert_never
17+
from typing import Any, TextIO
1818

1919
import cibuildwheel
20-
import cibuildwheel.linux
21-
import cibuildwheel.macos
22-
import cibuildwheel.pyodide
2320
import cibuildwheel.util
24-
import cibuildwheel.windows
2521
from cibuildwheel import errors
2622
from cibuildwheel.architecture import Architecture, allowed_architectures_check
2723
from cibuildwheel.ci import CIProvider, detect_ci_provider, fix_ansi_codes_for_github_actions
2824
from cibuildwheel.logger import log
2925
from cibuildwheel.options import CommandLineArguments, Options, compute_options
30-
from cibuildwheel.selector import BuildSelector, EnableGroup
31-
from cibuildwheel.typing import PLATFORMS, GenericPythonConfiguration, PlatformName
26+
from cibuildwheel.platforms import ALL_PLATFORM_MODULES, get_build_identifiers, get_platform_module
27+
from cibuildwheel.selector import BuildSelector, EnableGroup, selector_matches
28+
from cibuildwheel.typing import PLATFORMS, PlatformName
3229
from cibuildwheel.util.file import CIBW_CACHE_PATH
3330
from cibuildwheel.util.helpers import strtobool
3431

@@ -284,28 +281,6 @@ def _compute_platform(args: CommandLineArguments) -> PlatformName:
284281
return _compute_platform_auto()
285282

286283

287-
class PlatformModule(Protocol):
288-
# note that as per PEP544, the self argument is ignored when the protocol
289-
# is applied to a module
290-
def get_python_configurations(
291-
self, build_selector: BuildSelector, architectures: Set[Architecture]
292-
) -> Sequence[GenericPythonConfiguration]: ...
293-
294-
def build(self, options: Options, tmp_path: Path) -> None: ...
295-
296-
297-
def get_platform_module(platform: PlatformName) -> PlatformModule:
298-
if platform == "linux":
299-
return cibuildwheel.linux
300-
if platform == "windows":
301-
return cibuildwheel.windows
302-
if platform == "macos":
303-
return cibuildwheel.macos
304-
if platform == "pyodide":
305-
return cibuildwheel.pyodide
306-
assert_never(platform)
307-
308-
309284
@contextlib.contextmanager
310285
def print_new_wheels(msg: str, output_dir: Path) -> Generator[None, None, None]:
311286
"""
@@ -445,15 +420,6 @@ def print_preamble(platform: str, options: Options, identifiers: Sequence[str])
445420
print("Here we go!\n")
446421

447422

448-
def get_build_identifiers(
449-
platform_module: PlatformModule,
450-
build_selector: BuildSelector,
451-
architectures: Set[Architecture],
452-
) -> list[str]:
453-
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
454-
return [config.identifier for config in python_configurations]
455-
456-
457423
def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str]:
458424
warnings = []
459425

@@ -479,6 +445,48 @@ def detect_warnings(*, options: Options, identifiers: Iterable[str]) -> list[str
479445
)
480446
raise errors.ConfigurationError(msg)
481447

448+
build_selector = options.globals.build_selector
449+
test_selector = options.globals.test_selector
450+
451+
warnings += check_for_invalid_selectors("build", build_selector.build_config, error=True)
452+
warnings += check_for_invalid_selectors("skip", build_selector.skip_config)
453+
warnings += check_for_invalid_selectors("test_skip", test_selector.skip_config)
454+
455+
return warnings
456+
457+
458+
def check_for_invalid_selectors(
459+
selector_name: str, selector_value: str, *, error: bool = False
460+
) -> list[str]:
461+
warnings = []
462+
463+
all_valid_identifiers = [
464+
identifier
465+
for name, module in ALL_PLATFORM_MODULES.items()
466+
for identifier in get_build_identifiers(
467+
platform_module=module,
468+
architectures=Architecture.all_archs(name),
469+
build_selector=BuildSelector(build_config="*", skip_config=""),
470+
)
471+
]
472+
473+
for selector in selector_value.split():
474+
if not any(selector_matches(selector, i) for i in all_valid_identifiers):
475+
msg = f"Invalid `{selector_name}` selector: {selector!r}. "
476+
error_type: type = errors.ConfigurationError
477+
478+
if "p2" in selector or "p35" in selector:
479+
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update `{selector_name}`"
480+
error_type = errors.DeprecationError
481+
if "p36" in selector or "p37" in selector:
482+
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update `{selector_name}`"
483+
error_type = errors.DeprecationError
484+
485+
if error:
486+
raise error_type(msg)
487+
488+
warnings.append(msg)
489+
482490
return warnings
483491

484492

cibuildwheel/options.py

+1-24
Original file line numberDiff line numberDiff line change
@@ -839,14 +839,6 @@ def check_for_invalid_configuration(self, identifiers: Iterable[str]) -> None:
839839
)
840840
)
841841

842-
def check_for_deprecated_options(self) -> None:
843-
build_selector = self.globals.build_selector
844-
test_selector = self.globals.test_selector
845-
846-
deprecated_selectors("CIBW_BUILD", build_selector.build_config, error=True)
847-
deprecated_selectors("CIBW_SKIP", build_selector.skip_config)
848-
deprecated_selectors("CIBW_TEST_SKIP", test_selector.skip_config)
849-
850842
@functools.cached_property
851843
def defaults(self) -> Options:
852844
return Options(
@@ -959,9 +951,7 @@ def compute_options(
959951
command_line_arguments: CommandLineArguments,
960952
env: Mapping[str, str],
961953
) -> Options:
962-
options = Options(platform=platform, command_line_arguments=command_line_arguments, env=env)
963-
options.check_for_deprecated_options()
964-
return options
954+
return Options(platform=platform, command_line_arguments=command_line_arguments, env=env)
965955

966956

967957
@functools.cache
@@ -976,16 +966,3 @@ def _get_pinned_container_images() -> Mapping[str, Mapping[str, str]]:
976966
all_pinned_images = configparser.ConfigParser()
977967
all_pinned_images.read(resources.PINNED_DOCKER_IMAGES)
978968
return all_pinned_images
979-
980-
981-
def deprecated_selectors(name: str, selector: str, *, error: bool = False) -> None:
982-
if "p2" in selector or "p35" in selector:
983-
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 1.x series or update {name}"
984-
if error:
985-
raise errors.DeprecationError(msg)
986-
log.warning(msg)
987-
if "p36" in selector or "p37" in selector:
988-
msg = f"cibuildwheel 3.x no longer supports Python < 3.8. Please use the 2.x series or update {name}"
989-
if error:
990-
raise errors.DeprecationError(msg)
991-
log.warning(msg)

cibuildwheel/platforms/__init__.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Sequence
4+
from pathlib import Path
5+
from typing import Final, Protocol, assert_never
6+
7+
from cibuildwheel.architecture import Architecture
8+
from cibuildwheel.options import Options
9+
from cibuildwheel.platforms import linux, macos, pyodide, windows
10+
from cibuildwheel.selector import BuildSelector
11+
from cibuildwheel.typing import GenericPythonConfiguration, PlatformName
12+
13+
14+
class PlatformModule(Protocol):
15+
# note that as per PEP544, the self argument is ignored when the protocol
16+
# is applied to a module
17+
def get_python_configurations(
18+
self, build_selector: BuildSelector, architectures: set[Architecture]
19+
) -> Sequence[GenericPythonConfiguration]: ...
20+
21+
def build(self, options: Options, tmp_path: Path) -> None: ...
22+
23+
24+
def get_platform_module(platform: PlatformName) -> PlatformModule:
25+
if platform == "linux":
26+
return linux
27+
if platform == "windows":
28+
return windows
29+
if platform == "macos":
30+
return macos
31+
if platform == "pyodide":
32+
return pyodide
33+
assert_never(platform)
34+
35+
36+
ALL_PLATFORM_MODULES: Final[dict[PlatformName, PlatformModule]] = {
37+
"linux": linux,
38+
"windows": windows,
39+
"macos": macos,
40+
"pyodide": pyodide,
41+
}
42+
43+
44+
def get_build_identifiers(
45+
platform_module: PlatformModule,
46+
build_selector: BuildSelector,
47+
architectures: set[Architecture],
48+
) -> list[str]:
49+
python_configurations = platform_module.get_python_configurations(build_selector, architectures)
50+
return [config.identifier for config in python_configurations]

cibuildwheel/linux.py cibuildwheel/platforms/linux.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212

1313
from packaging.version import Version
1414

15-
from . import errors
16-
from .architecture import Architecture
17-
from .frontend import BuildFrontendConfig, get_build_frontend_extra_flags
18-
from .logger import log
19-
from .oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
20-
from .options import BuildOptions, Options
21-
from .selector import BuildSelector
22-
from .typing import PathOrStr
23-
from .util import resources
24-
from .util.file import copy_test_sources
25-
from .util.helpers import prepare_command, unwrap
26-
from .util.packaging import find_compatible_wheel
15+
from .. import errors
16+
from ..architecture import Architecture
17+
from ..frontend import BuildFrontendConfig, get_build_frontend_extra_flags
18+
from ..logger import log
19+
from ..oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
20+
from ..options import BuildOptions, Options
21+
from ..selector import BuildSelector
22+
from ..typing import PathOrStr
23+
from ..util import resources
24+
from ..util.file import copy_test_sources
25+
from ..util.helpers import prepare_command, unwrap
26+
from ..util.packaging import find_compatible_wheel
2727

2828
ARCHITECTURE_OCI_PLATFORM_MAP = {
2929
Architecture.x86_64: OCIPlatform.AMD64,

cibuildwheel/macos.py cibuildwheel/platforms/macos.py

+15-15
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@
1717
from filelock import FileLock
1818
from packaging.version import Version
1919

20-
from . import errors
21-
from .architecture import Architecture
22-
from .ci import detect_ci_provider
23-
from .environment import ParsedEnvironment
24-
from .frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
25-
from .logger import log
26-
from .options import Options
27-
from .selector import BuildSelector
28-
from .typing import PathOrStr
29-
from .util import resources
30-
from .util.cmd import call, shell
31-
from .util.file import (
20+
from .. import errors
21+
from ..architecture import Architecture
22+
from ..ci import detect_ci_provider
23+
from ..environment import ParsedEnvironment
24+
from ..frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
25+
from ..logger import log
26+
from ..options import Options
27+
from ..selector import BuildSelector
28+
from ..typing import PathOrStr
29+
from ..util import resources
30+
from ..util.cmd import call, shell
31+
from ..util.file import (
3232
CIBW_CACHE_PATH,
3333
copy_test_sources,
3434
download,
3535
move_file,
3636
)
37-
from .util.helpers import prepare_command, unwrap
38-
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
39-
from .venv import find_uv, virtualenv
37+
from ..util.helpers import prepare_command, unwrap
38+
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
39+
from ..venv import find_uv, virtualenv
4040

4141

4242
@functools.cache

cibuildwheel/pyodide.py cibuildwheel/platforms/pyodide.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,27 @@
1313

1414
from filelock import FileLock
1515

16-
from . import errors
17-
from .architecture import Architecture
18-
from .environment import ParsedEnvironment
19-
from .frontend import BuildFrontendConfig, get_build_frontend_extra_flags
20-
from .logger import log
21-
from .options import Options
22-
from .selector import BuildSelector
23-
from .typing import PathOrStr
24-
from .util import resources
25-
from .util.cmd import call, shell
26-
from .util.file import (
16+
from .. import errors
17+
from ..architecture import Architecture
18+
from ..environment import ParsedEnvironment
19+
from ..frontend import BuildFrontendConfig, get_build_frontend_extra_flags
20+
from ..logger import log
21+
from ..options import Options
22+
from ..selector import BuildSelector
23+
from ..typing import PathOrStr
24+
from ..util import resources
25+
from ..util.cmd import call, shell
26+
from ..util.file import (
2727
CIBW_CACHE_PATH,
2828
copy_test_sources,
2929
download,
3030
extract_tar,
3131
extract_zip,
3232
move_file,
3333
)
34-
from .util.helpers import prepare_command
35-
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
36-
from .venv import virtualenv
34+
from ..util.helpers import prepare_command
35+
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
36+
from ..venv import virtualenv
3737

3838
IS_WIN: Final[bool] = sys.platform.startswith("win")
3939

cibuildwheel/windows.py cibuildwheel/platforms/windows.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@
1414
from filelock import FileLock
1515
from packaging.version import Version
1616

17-
from . import errors
18-
from .architecture import Architecture
19-
from .environment import ParsedEnvironment
20-
from .frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
21-
from .logger import log
22-
from .options import Options
23-
from .selector import BuildSelector
24-
from .typing import PathOrStr
25-
from .util import resources
26-
from .util.cmd import call, shell
27-
from .util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
28-
from .util.helpers import prepare_command, unwrap
29-
from .util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
30-
from .venv import find_uv, virtualenv
17+
from .. import errors
18+
from ..architecture import Architecture
19+
from ..environment import ParsedEnvironment
20+
from ..frontend import BuildFrontendConfig, BuildFrontendName, get_build_frontend_extra_flags
21+
from ..logger import log
22+
from ..options import Options
23+
from ..selector import BuildSelector
24+
from ..typing import PathOrStr
25+
from ..util import resources
26+
from ..util.cmd import call, shell
27+
from ..util.file import CIBW_CACHE_PATH, copy_test_sources, download, extract_zip, move_file
28+
from ..util.helpers import prepare_command, unwrap
29+
from ..util.packaging import combine_constraints, find_compatible_wheel, get_pip_version
30+
from ..venv import find_uv, virtualenv
3131

3232

3333
def get_nuget_args(

unit_test/get_platform_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from cibuildwheel.ci import CIProvider, detect_ci_provider
99
from cibuildwheel.errors import FatalError
10-
from cibuildwheel.windows import PythonConfiguration, setup_setuptools_cross_compile
10+
from cibuildwheel.platforms.windows import PythonConfiguration, setup_setuptools_cross_compile
1111

1212
# monkeypatching os.name is too flaky. E.g. It works on my machine, but fails in pipeline
1313
if not sys.platform.startswith("win"):

0 commit comments

Comments
 (0)