Skip to content

Commit a70d4b3

Browse files
committed
WIP: start adding enable
Signed-off-by: Henry Schreiner <[email protected]>
1 parent 4e93d91 commit a70d4b3

File tree

7 files changed

+112
-29
lines changed

7 files changed

+112
-29
lines changed

bin/generate_schema.py

+16
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
- append
2727
default: none
2828
description: How to inherit the parent's value.
29+
enable:
30+
enum:
31+
- cpython-eol
32+
- cpython-free-threaded
33+
- cpython-prerelease
34+
- pypy-eol
35+
description: A Python version or flavor to enable.
2936
additionalProperties: false
3037
description: cibuildwheel's settings.
3138
type: object
@@ -99,6 +106,13 @@
99106
default: pinned
100107
description: Specify how cibuildwheel controls the versions of the tools it uses
101108
type: string
109+
enable:
110+
description: Enable or disable certain builds.
111+
oneOf:
112+
- $ref: "#/$defs/enable"
113+
- type: array
114+
items:
115+
$ref: "#/$defs/enable"
102116
environment:
103117
description: Set environment variables needed during the build.
104118
type: string_table
@@ -110,6 +124,7 @@
110124
type: boolean
111125
default: false
112126
description: The project supports free-threaded builds of Python (PEP703)
127+
deprecated: Use the `enable` option instead.
113128
manylinux-aarch64-image:
114129
type: string
115130
description: Specify alternative manylinux / musllinux container images
@@ -258,6 +273,7 @@
258273
del non_global_options["skip"]
259274
del non_global_options["test-skip"]
260275
del non_global_options["free-threaded-support"]
276+
del non_global_options["enable"]
261277

262278
overrides["items"]["properties"]["select"]["oneOf"] = string_array
263279
overrides["items"]["properties"] |= non_global_options.copy()

cibuildwheel/options.py

+31-8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
BuildFrontendConfig,
3131
BuildSelector,
3232
DependencyConstraints,
33+
EnableGroups,
3334
TestSelector,
3435
format_safe,
3536
resources_dir,
@@ -511,6 +512,7 @@ def get(
511512
env_plat: bool = True,
512513
option_format: OptionFormat | None = None,
513514
ignore_empty: bool = False,
515+
env_rule: InheritRule = InheritRule.NONE,
514516
) -> str:
515517
"""
516518
Get and return the value for the named option from environment,
@@ -542,8 +544,8 @@ def get(
542544
(o.options.get(name), o.inherit.get(name, InheritRule.NONE))
543545
for o in self.active_config_overrides
544546
],
545-
(self.env.get(envvar), InheritRule.NONE),
546-
(self.env.get(plat_envvar) if env_plat else None, InheritRule.NONE),
547+
(self.env.get(envvar), env_rule),
548+
(self.env.get(plat_envvar) if env_plat else None, env_rule),
547549
ignore_empty=ignore_empty,
548550
option_format=option_format,
549551
)
@@ -599,23 +601,46 @@ def globals(self) -> GlobalOptions:
599601
skip_config = self.reader.get("skip", env_plat=False, option_format=ListFormat(sep=" "))
600602
test_skip = self.reader.get("test-skip", env_plat=False, option_format=ListFormat(sep=" "))
601603

604+
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
605+
606+
enable_groups = self.reader.get(
607+
"enable", env_plat=False, option_format=ListFormat(sep=" "), env_rule=InheritRule.APPEND
608+
)
609+
enable = {EnableGroups(group) for group in enable_groups.split()}
610+
602611
free_threaded_support = strtobool(
603612
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
604613
)
605614

606-
allow_empty = args.allow_empty or strtobool(self.env.get("CIBW_ALLOW_EMPTY", "0"))
607-
608615
prerelease_pythons = args.prerelease_pythons or strtobool(
609616
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
610617
)
611618

619+
if enable and (free_threaded_support or prerelease_pythons):
620+
msg = (
621+
"free-threaded-support and prerelease-pythons should be specified by enable instead"
622+
)
623+
raise OptionsReaderError(msg)
624+
625+
if free_threaded_support:
626+
enable.add(EnableGroups.CPythonFreeThreaded)
627+
if prerelease_pythons:
628+
enable.add(EnableGroups.CPythonPrerelease)
629+
630+
# For backwards compatibility, we are adding EoL Python versions to the enable group for one more release.
631+
enable |= {EnableGroups.CPythonEoL, EnableGroups.PyPyEoL}
632+
612633
# This is not supported in tool.cibuildwheel, as it comes from a standard location.
613634
# Passing this in as an environment variable will override pyproject.toml, setup.cfg, or setup.py
614635
requires_python_str: str | None = (
615636
self.env.get("CIBW_PROJECT_REQUIRES_PYTHON") or self.package_requires_python_str
616637
)
617638
requires_python = None if requires_python_str is None else SpecifierSet(requires_python_str)
618639

640+
# Requires-python overrides cpython-eol
641+
if requires_python is not None:
642+
enable.add(EnableGroups.CPythonEoL)
643+
619644
archs_config_str = args.archs or self.reader.get("archs", option_format=ListFormat(sep=" "))
620645
architectures = Architecture.parse_config(archs_config_str, platform=self.platform)
621646

@@ -624,15 +649,13 @@ def globals(self) -> GlobalOptions:
624649
build_config = args.only
625650
skip_config = ""
626651
architectures = Architecture.all_archs(self.platform)
627-
prerelease_pythons = True
628-
free_threaded_support = True
652+
enable = set(EnableGroups)
629653

630654
build_selector = BuildSelector(
631655
build_config=build_config,
632656
skip_config=skip_config,
633657
requires_python=requires_python,
634-
prerelease_pythons=prerelease_pythons,
635-
free_threaded_support=free_threaded_support,
658+
enable=frozenset(enable),
636659
)
637660
test_selector = TestSelector(skip_config=test_skip)
638661

cibuildwheel/resources/cibuildwheel.schema.json

+25-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@
1010
],
1111
"default": "none",
1212
"description": "How to inherit the parent's value."
13-
}
13+
},
14+
"enable": {
15+
"enum": [
16+
"cpython-eol",
17+
"cpython-free-threaded",
18+
"cpython-prerelease",
19+
"pypy-eol"
20+
]
21+
},
22+
"description": "A Python version or flavor to enable."
1423
},
1524
"additionalProperties": false,
1625
"description": "cibuildwheel's settings.",
@@ -228,6 +237,21 @@
228237
"type": "string",
229238
"title": "CIBW_DEPENDENCY_VERSIONS"
230239
},
240+
"enable": {
241+
"description": "Enable or disable certain builds.",
242+
"oneOf": [
243+
{
244+
"$ref": "#/$defs/enable"
245+
},
246+
{
247+
"type": "array",
248+
"items": {
249+
"$ref": "#/$defs/enable"
250+
}
251+
}
252+
],
253+
"title": "CIBW_ENABLE"
254+
},
231255
"environment": {
232256
"description": "Set environment variables needed during the build.",
233257
"oneOf": [

cibuildwheel/resources/defaults.toml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ build = "*"
33
skip = ""
44
test-skip = ""
55
free-threaded-support = false
6+
enable = []
67

78
archs = ["auto"]
89
build-frontend = "default"

cibuildwheel/util.py

+29-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import contextlib
4+
import enum
45
import fnmatch
56
import itertools
67
import os
@@ -23,7 +24,7 @@
2324
from pathlib import Path, PurePath
2425
from tempfile import TemporaryDirectory
2526
from time import sleep
26-
from typing import Any, ClassVar, Final, Literal, TextIO, TypeVar
27+
from typing import Any, Final, Literal, TextIO, TypeVar
2728
from zipfile import ZipFile
2829

2930
import bracex
@@ -41,6 +42,7 @@
4142

4243
__all__ = [
4344
"MANYLINUX_ARCHS",
45+
"EnableGroups",
4446
"call",
4547
"chdir",
4648
"combine_constraints",
@@ -66,6 +68,17 @@
6668
test_fail_cwd_file: Final[Path] = resources_dir / "testing_temp_dir_file.py"
6769

6870

71+
class EnableGroups(enum.Enum):
72+
"""
73+
Groups of build selectors that are not enabled by default.
74+
"""
75+
76+
CPythonEoL = "cpython-eol"
77+
CPythonFreeThreaded = "cpython-free-threaded"
78+
CPythonPrerelease = "cpython-prerelease"
79+
PyPyEoL = "pypy-eol"
80+
81+
6982
MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
7083
"x86_64",
7184
"i686",
@@ -247,12 +260,7 @@ class BuildSelector:
247260
build_config: str
248261
skip_config: str
249262
requires_python: SpecifierSet | None = None
250-
251-
# a pattern that skips prerelease versions, when include_prereleases is False.
252-
PRERELEASE_SKIP: ClassVar[str] = ""
253-
prerelease_pythons: bool = False
254-
255-
free_threaded_support: bool = False
263+
enable: frozenset[EnableGroups] = frozenset()
256264

257265
def __call__(self, build_id: str) -> bool:
258266
# Filter build selectors by python_requires if set
@@ -266,12 +274,20 @@ def __call__(self, build_id: str) -> bool:
266274
if not self.requires_python.contains(version):
267275
return False
268276

269-
# filter out the prerelease pythons if self.prerelease_pythons is False
270-
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
277+
# filter out groups that are not enabled
278+
if EnableGroups.CPythonEoL not in self.enable and selector_matches(
279+
"cp3{6,7,8}-*", build_id
280+
):
271281
return False
272-
273-
# filter out free threaded pythons if self.free_threaded_support is False
274-
if not self.free_threaded_support and selector_matches("*t-*", build_id):
282+
if EnableGroups.CPythonFreeThreaded not in self.enable and selector_matches(
283+
"cp3??t-*", build_id
284+
):
285+
return False
286+
if EnableGroups.CPythonPrerelease not in self.enable and selector_matches(
287+
"cp314*", build_id
288+
):
289+
return False
290+
if EnableGroups.PyPyEoL not in self.enable and selector_matches("pp3{7,8,9}-*", build_id):
275291
return False
276292

277293
should_build = selector_matches(self.build_config, build_id)
@@ -284,8 +300,7 @@ def options_summary(self) -> Any:
284300
"build_config": self.build_config,
285301
"skip_config": self.skip_config,
286302
"requires_python": str(self.requires_python),
287-
"prerelease_pythons": self.prerelease_pythons,
288-
"free_threaded_support": self.free_threaded_support,
303+
"enable": sorted(group.value for group in self.enable),
289304
}
290305

291306

unit_test/build_selector_test.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from packaging.specifiers import SpecifierSet
44

5-
from cibuildwheel.util import BuildSelector
5+
from cibuildwheel.util import BuildSelector, EnableGroups
66

77

88
def test_build():
@@ -43,7 +43,9 @@ def test_build_filter_pre():
4343
build_selector = BuildSelector(
4444
build_config="cp3*-* *-manylinux*",
4545
skip_config="",
46-
prerelease_pythons=True,
46+
enable=frozenset(
47+
[EnableGroups.CPythonPrerelease, EnableGroups.CPythonEoL, EnableGroups.PyPyEoL]
48+
),
4749
)
4850

4951
assert build_selector("cp37-manylinux_x86_64")
@@ -146,9 +148,7 @@ def test_build_limited_python_patch():
146148

147149

148150
def test_build_free_threaded_python():
149-
build_selector = BuildSelector(
150-
build_config="*", skip_config="", prerelease_pythons=True, free_threaded_support=True
151-
)
151+
build_selector = BuildSelector(build_config="*", skip_config="", enable=frozenset(EnableGroups))
152152

153153
assert build_selector("cp313t-manylinux_x86_64")
154154

unit_test/options_test.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
Options,
1616
_get_pinned_container_images,
1717
)
18+
from cibuildwheel.util import EnableGroups
1819

1920
PYPROJECT_1 = """
2021
[tool.cibuildwheel]
@@ -448,4 +449,7 @@ def test_free_threaded_support(
448449
)
449450
)
450451
options = Options(platform="linux", command_line_arguments=args, env=env)
451-
assert options.globals.build_selector.free_threaded_support is expected_result
452+
if expected_result:
453+
assert EnableGroups.CPythonFreeThreaded in options.globals.build_selector.enable
454+
else:
455+
assert EnableGroups.CPythonFreeThreaded not in options.globals.build_selector.enable

0 commit comments

Comments
 (0)