From cc80f2cd66fb7846320612e33a0e90f0832079c3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 19 Oct 2024 00:48:49 -0400 Subject: [PATCH] feat: adding enable Signed-off-by: Henry Schreiner --- bin/generate_schema.py | 15 ++++++++ cibuildwheel/options.py | 37 ++++++++++++++---- .../resources/cibuildwheel.schema.json | 26 ++++++++++++- cibuildwheel/resources/defaults.toml | 1 + cibuildwheel/util.py | 38 ++++++++++++------- unit_test/build_selector_test.py | 8 ++-- unit_test/options_test.py | 6 ++- 7 files changed, 102 insertions(+), 29 deletions(-) diff --git a/bin/generate_schema.py b/bin/generate_schema.py index 41f4ad4cd..fef46428f 100755 --- a/bin/generate_schema.py +++ b/bin/generate_schema.py @@ -26,6 +26,12 @@ - append default: none description: How to inherit the parent's value. + enable: + enum: + - cpython-free-threaded + - cpython-prerelease + - pypy + description: A Python version or flavor to enable. additionalProperties: false description: cibuildwheel's settings. type: object @@ -99,6 +105,13 @@ default: pinned description: Specify how cibuildwheel controls the versions of the tools it uses type: string + enable: + description: Enable or disable certain builds. + oneOf: + - $ref: "#/$defs/enable" + - type: array + items: + $ref: "#/$defs/enable" environment: description: Set environment variables needed during the build. type: string_table @@ -110,6 +123,7 @@ type: boolean default: false description: The project supports free-threaded builds of Python (PEP703) + deprecated: Use the `enable` option instead. manylinux-aarch64-image: type: string description: Specify alternative manylinux / musllinux container images @@ -258,6 +272,7 @@ del non_global_options["skip"] del non_global_options["test-skip"] del non_global_options["free-threaded-support"] +del non_global_options["enable"] overrides["items"]["properties"]["select"]["oneOf"] = string_array overrides["items"]["properties"] |= non_global_options.copy() diff --git a/cibuildwheel/options.py b/cibuildwheel/options.py index 5e1e71d16..bd5e9e6fd 100644 --- a/cibuildwheel/options.py +++ b/cibuildwheel/options.py @@ -30,6 +30,7 @@ BuildFrontendConfig, BuildSelector, DependencyConstraints, + EnableGroups, TestSelector, format_safe, resources_dir, @@ -511,6 +512,7 @@ def get( env_plat: bool = True, option_format: OptionFormat | None = None, ignore_empty: bool = False, + env_rule: InheritRule = InheritRule.NONE, ) -> str: """ Get and return the value for the named option from environment, @@ -542,8 +544,8 @@ def get( (o.options.get(name), o.inherit.get(name, InheritRule.NONE)) for o in self.active_config_overrides ], - (self.env.get(envvar), InheritRule.NONE), - (self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE), + (self.env.get(envvar), env_rule), + (self.env.get(plat_envvar) if env_plat else None, env_rule), ignore_empty=ignore_empty, option_format=option_format, ) @@ -599,16 +601,37 @@ def globals(self) -> GlobalOptions: skip_config = self.reader.get("skip", env_plat=False, option_format=ListFormat(sep=" ")) test_skip = self.reader.get("test-skip", env_plat=False, option_format=ListFormat(sep=" ")) + allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0")) + + enable_groups = self.reader.get( + "enable", env_plat=False, option_format=ListFormat(sep=" "), env_rule=InheritRule.APPEND + ) + enable = {EnableGroups(group) for group in enable_groups.split()} + free_threaded_support = strtobool( self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True) ) - allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0")) - prerelease_pythons = args.prerelease_pythons or strtobool( self.env.get("CIBW_PRERELEASE_PYTHONS", "0") ) + if free_threaded_support or prerelease_pythons: + msg = ( + "free-threaded-support and prerelease-pythons should be specified by enable instead" + ) + if enable: + raise OptionsReaderError(msg) + log.warning(msg) + + if free_threaded_support: + enable.add(EnableGroups.CPythonFreeThreaded) + if prerelease_pythons: + enable.add(EnableGroups.CPythonPrerelease) + + # For backwards compatibility, we are adding PyPy for now + enable |= {EnableGroups.PyPy} + # This is not supported in tool.cibuildwheel, as it comes from a standard location. # Passing this in as an environment variable will override pyproject.toml, setup.cfg, or setup.py requires_python_str: str | None = ( @@ -624,15 +647,13 @@ def globals(self) -> GlobalOptions: build_config = args.only skip_config = "" architectures = Architecture.all_archs(self.platform) - prerelease_pythons = True - free_threaded_support = True + enable = set(EnableGroups) build_selector = BuildSelector( build_config=build_config, skip_config=skip_config, requires_python=requires_python, - prerelease_pythons=prerelease_pythons, - free_threaded_support=free_threaded_support, + enable=frozenset(enable), ) test_selector = TestSelector(skip_config=test_skip) diff --git a/cibuildwheel/resources/cibuildwheel.schema.json b/cibuildwheel/resources/cibuildwheel.schema.json index 8e2508bc9..a4394a713 100644 --- a/cibuildwheel/resources/cibuildwheel.schema.json +++ b/cibuildwheel/resources/cibuildwheel.schema.json @@ -10,7 +10,16 @@ ], "default": "none", "description": "How to inherit the parent's value." - } + }, + "enable": { + "enum": [ + "cpython-eol", + "cpython-free-threaded", + "cpython-prerelease", + "pypy-eol" + ] + }, + "description": "A Python version or flavor to enable." }, "additionalProperties": false, "description": "cibuildwheel's settings.", @@ -228,6 +237,21 @@ "type": "string", "title": "CIBW_DEPENDENCY_VERSIONS" }, + "enable": { + "description": "Enable or disable certain builds.", + "oneOf": [ + { + "$ref": "#/$defs/enable" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/enable" + } + } + ], + "title": "CIBW_ENABLE" + }, "environment": { "description": "Set environment variables needed during the build.", "oneOf": [ diff --git a/cibuildwheel/resources/defaults.toml b/cibuildwheel/resources/defaults.toml index 21bac7a0c..1303b793d 100644 --- a/cibuildwheel/resources/defaults.toml +++ b/cibuildwheel/resources/defaults.toml @@ -3,6 +3,7 @@ build = "*" skip = "" test-skip = "" free-threaded-support = false +enable = [] archs = ["auto"] build-frontend = "default" diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index bfbe50c7a..9436e4a44 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -1,6 +1,7 @@ from __future__ import annotations import contextlib +import enum import fnmatch import itertools import os @@ -23,7 +24,7 @@ from pathlib import Path, PurePath from tempfile import TemporaryDirectory from time import sleep -from typing import Any, ClassVar, Final, Literal, TextIO, TypeVar +from typing import Any, Final, Literal, TextIO, TypeVar from zipfile import ZipFile import bracex @@ -41,6 +42,7 @@ __all__ = [ "MANYLINUX_ARCHS", + "EnableGroups", "call", "chdir", "combine_constraints", @@ -66,6 +68,16 @@ test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py" +class EnableGroups(enum.Enum): + """ + Groups of build selectors that are not enabled by default. + """ + + CPythonFreeThreaded = "cpython-free-threaded" + CPythonPrerelease = "cpython-prerelease" + PyPy = "pypy" + + MANYLINUX_ARCHS: Final[tuple[str, ...]] = ( "x86_64", "i686", @@ -247,12 +259,7 @@ class BuildSelector: build_config: str skip_config: str requires_python: SpecifierSet | None = None - - # a pattern that skips prerelease versions, when include_prereleases is False. - PRERELEASE_SKIP: ClassVar[str] = "" - prerelease_pythons: bool = False - - free_threaded_support: bool = False + enable: frozenset[EnableGroups] = frozenset() def __call__(self, build_id: str) -> bool: # Filter build selectors by python_requires if set @@ -266,12 +273,16 @@ def __call__(self, build_id: str) -> bool: if not self.requires_python.contains(version): return False - # filter out the prerelease pythons if self.prerelease_pythons is False - if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id): + # filter out groups that are not enabled + if EnableGroups.CPythonFreeThreaded not in self.enable and selector_matches( + "cp3??t-*", build_id + ): return False - - # filter out free threaded pythons if self.free_threaded_support is False - if not self.free_threaded_support and selector_matches("*t-*", build_id): + if EnableGroups.CPythonPrerelease not in self.enable and selector_matches( + "cp314*", build_id + ): + return False + if EnableGroups.PyPy not in self.enable and selector_matches("pp*", build_id): return False should_build = selector_matches(self.build_config, build_id) @@ -284,8 +295,7 @@ def options_summary(self) -> Any: "build_config": self.build_config, "skip_config": self.skip_config, "requires_python": str(self.requires_python), - "prerelease_pythons": self.prerelease_pythons, - "free_threaded_support": self.free_threaded_support, + "enable": sorted(group.value for group in self.enable), } diff --git a/unit_test/build_selector_test.py b/unit_test/build_selector_test.py index f89222461..2df2e5a03 100644 --- a/unit_test/build_selector_test.py +++ b/unit_test/build_selector_test.py @@ -2,7 +2,7 @@ from packaging.specifiers import SpecifierSet -from cibuildwheel.util import BuildSelector +from cibuildwheel.util import BuildSelector, EnableGroups def test_build(): @@ -43,7 +43,7 @@ def test_build_filter_pre(): build_selector = BuildSelector( build_config="cp3*-* *-manylinux*", skip_config="", - prerelease_pythons=True, + enable=frozenset([EnableGroups.CPythonPrerelease, EnableGroups.PyPy]), ) assert build_selector("cp37-manylinux_x86_64") @@ -146,9 +146,7 @@ def test_build_limited_python_patch(): def test_build_free_threaded_python(): - build_selector = BuildSelector( - build_config="*", skip_config="", prerelease_pythons=True, free_threaded_support=True - ) + build_selector = BuildSelector(build_config="*", skip_config="", enable=frozenset(EnableGroups)) assert build_selector("cp313t-manylinux_x86_64") diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 061396552..8cae1defa 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -15,6 +15,7 @@ Options, _get_pinned_container_images, ) +from cibuildwheel.util import EnableGroups PYPROJECT_1 = """ [tool.cibuildwheel] @@ -454,4 +455,7 @@ def test_free_threaded_support( ) ) options = Options(platform="linux", command_line_arguments=args, env=env) - assert options.globals.build_selector.free_threaded_support is expected_result + if expected_result: + assert EnableGroups.CPythonFreeThreaded in options.globals.build_selector.enable + else: + assert EnableGroups.CPythonFreeThreaded not in options.globals.build_selector.enable