feat: add option to opt-in free-threaded builds
This commit is contained in:
@@ -104,6 +104,10 @@ properties:
|
|||||||
description: Set environment variables on the host to pass-through to the container
|
description: Set environment variables on the host to pass-through to the container
|
||||||
during the build.
|
during the build.
|
||||||
type: string_array
|
type: string_array
|
||||||
|
free-threaded-support:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: The project supports free-threaded builds of Python (PEP703)
|
||||||
manylinux-aarch64-image:
|
manylinux-aarch64-image:
|
||||||
type: string
|
type: string
|
||||||
description: Specify alternative manylinux / musllinux container images
|
description: Specify alternative manylinux / musllinux container images
|
||||||
@@ -248,6 +252,7 @@ non_global_options = {k: {"$ref": f"#/properties/{k}"} for k in schema["properti
|
|||||||
del non_global_options["build"]
|
del non_global_options["build"]
|
||||||
del non_global_options["skip"]
|
del non_global_options["skip"]
|
||||||
del non_global_options["test-skip"]
|
del non_global_options["test-skip"]
|
||||||
|
del non_global_options["free-threaded-support"]
|
||||||
|
|
||||||
overrides["items"]["properties"]["select"]["oneOf"] = string_array
|
overrides["items"]["properties"]["select"]["oneOf"] = string_array
|
||||||
overrides["items"]["properties"] |= non_global_options.copy()
|
overrides["items"]["properties"] |= non_global_options.copy()
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class BuildOptions:
|
|||||||
return self.globals.architectures
|
return self.globals.architectures
|
||||||
|
|
||||||
|
|
||||||
Setting = Union[Mapping[str, str], Sequence[str], str, int]
|
Setting = Union[Mapping[str, str], Sequence[str], str, int, bool]
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
@@ -196,7 +196,7 @@ def _resolve_cascade(
|
|||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ignore_empty and not value:
|
if ignore_empty and not value and value is not False:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
value_string = _stringify_setting(value, list_sep, table_format)
|
value_string = _stringify_setting(value, list_sep, table_format)
|
||||||
@@ -258,7 +258,7 @@ def _stringify_setting(
|
|||||||
raise ConfigOptionError(msg)
|
raise ConfigOptionError(msg)
|
||||||
return list_sep.join(setting)
|
return list_sep.join(setting)
|
||||||
|
|
||||||
if isinstance(setting, int):
|
if isinstance(setting, (bool, int)):
|
||||||
return str(setting)
|
return str(setting)
|
||||||
|
|
||||||
return setting
|
return setting
|
||||||
@@ -516,6 +516,10 @@ class Options:
|
|||||||
skip_config = self.reader.get("skip", env_plat=False, list_sep=" ")
|
skip_config = self.reader.get("skip", env_plat=False, list_sep=" ")
|
||||||
test_skip = self.reader.get("test-skip", env_plat=False, list_sep=" ")
|
test_skip = self.reader.get("test-skip", env_plat=False, list_sep=" ")
|
||||||
|
|
||||||
|
free_threaded_support = strtobool(
|
||||||
|
self.reader.get("free-threaded-support", env_plat=False, ignore_empty=True)
|
||||||
|
)
|
||||||
|
|
||||||
prerelease_pythons = args.prerelease_pythons or strtobool(
|
prerelease_pythons = args.prerelease_pythons or strtobool(
|
||||||
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
|
self.env.get("CIBW_PRERELEASE_PYTHONS", "0")
|
||||||
)
|
)
|
||||||
@@ -536,12 +540,14 @@ class Options:
|
|||||||
skip_config = ""
|
skip_config = ""
|
||||||
architectures = Architecture.all_archs(self.platform)
|
architectures = Architecture.all_archs(self.platform)
|
||||||
prerelease_pythons = True
|
prerelease_pythons = True
|
||||||
|
free_threaded_support = True
|
||||||
|
|
||||||
build_selector = BuildSelector(
|
build_selector = BuildSelector(
|
||||||
build_config=build_config,
|
build_config=build_config,
|
||||||
skip_config=skip_config,
|
skip_config=skip_config,
|
||||||
requires_python=requires_python,
|
requires_python=requires_python,
|
||||||
prerelease_pythons=prerelease_pythons,
|
prerelease_pythons=prerelease_pythons,
|
||||||
|
free_threaded_support=free_threaded_support,
|
||||||
)
|
)
|
||||||
test_selector = TestSelector(skip_config=test_skip)
|
test_selector = TestSelector(skip_config=test_skip)
|
||||||
|
|
||||||
|
|||||||
@@ -255,6 +255,12 @@
|
|||||||
],
|
],
|
||||||
"title": "CIBW_ENVIRONMENT_PASS"
|
"title": "CIBW_ENVIRONMENT_PASS"
|
||||||
},
|
},
|
||||||
|
"free-threaded-support": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "The project supports free-threaded builds of Python (PEP703)",
|
||||||
|
"title": "CIBW_FREE_THREADED_SUPPORT"
|
||||||
|
},
|
||||||
"manylinux-aarch64-image": {
|
"manylinux-aarch64-image": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specify alternative manylinux / musllinux container images",
|
"description": "Specify alternative manylinux / musllinux container images",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
build = "*"
|
build = "*"
|
||||||
skip = ""
|
skip = ""
|
||||||
test-skip = ""
|
test-skip = ""
|
||||||
|
free-threaded-support = false
|
||||||
|
|
||||||
archs = ["auto"]
|
archs = ["auto"]
|
||||||
build-frontend = "default"
|
build-frontend = "default"
|
||||||
|
|||||||
@@ -241,6 +241,8 @@ class BuildSelector:
|
|||||||
PRERELEASE_SKIP: ClassVar[str] = "cp313-* cp313t-*"
|
PRERELEASE_SKIP: ClassVar[str] = "cp313-* cp313t-*"
|
||||||
prerelease_pythons: bool = False
|
prerelease_pythons: bool = False
|
||||||
|
|
||||||
|
free_threaded_support: bool = False
|
||||||
|
|
||||||
def __call__(self, build_id: str) -> bool:
|
def __call__(self, build_id: str) -> bool:
|
||||||
# Filter build selectors by python_requires if set
|
# Filter build selectors by python_requires if set
|
||||||
if self.requires_python is not None:
|
if self.requires_python is not None:
|
||||||
@@ -257,6 +259,10 @@ class BuildSelector:
|
|||||||
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
|
if not self.prerelease_pythons and selector_matches(self.PRERELEASE_SKIP, build_id):
|
||||||
return False
|
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):
|
||||||
|
return False
|
||||||
|
|
||||||
should_build = selector_matches(self.build_config, build_id)
|
should_build = selector_matches(self.build_config, build_id)
|
||||||
should_skip = selector_matches(self.skip_config, build_id)
|
should_skip = selector_matches(self.skip_config, build_id)
|
||||||
|
|
||||||
@@ -268,6 +274,7 @@ class BuildSelector:
|
|||||||
"skip_config": self.skip_config,
|
"skip_config": self.skip_config,
|
||||||
"requires_python": str(self.requires_python),
|
"requires_python": str(self.requires_python),
|
||||||
"prerelease_pythons": self.prerelease_pythons,
|
"prerelease_pythons": self.prerelease_pythons,
|
||||||
|
"free_threaded_support": self.free_threaded_support,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ def cibuildwheel_get_build_identifiers(project_path, env=None, *, prerelease_pyt
|
|||||||
cmd = [sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)]
|
cmd = [sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)]
|
||||||
if prerelease_pythons:
|
if prerelease_pythons:
|
||||||
cmd.append("--prerelease-pythons")
|
cmd.append("--prerelease-pythons")
|
||||||
|
if env is None:
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.setdefault("CIBW_FREE_THREADED_SUPPORT", "1")
|
||||||
|
|
||||||
cmd_output = subprocess.run(
|
cmd_output = subprocess.run(
|
||||||
cmd,
|
cmd,
|
||||||
@@ -94,6 +97,8 @@ def cibuildwheel_run(
|
|||||||
|
|
||||||
_update_pip_cache_dir(env)
|
_update_pip_cache_dir(env)
|
||||||
|
|
||||||
|
env.setdefault("CIBW_FREE_THREADED_SUPPORT", "1")
|
||||||
|
|
||||||
with TemporaryDirectory() as tmp_output_dir:
|
with TemporaryDirectory() as tmp_output_dir:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ def test_build_filter_pre():
|
|||||||
assert build_selector("cp313-manylinux_x86_64")
|
assert build_selector("cp313-manylinux_x86_64")
|
||||||
assert build_selector("cp37-win_amd64")
|
assert build_selector("cp37-win_amd64")
|
||||||
assert build_selector("cp313-win_amd64")
|
assert build_selector("cp313-win_amd64")
|
||||||
|
assert not build_selector("cp313t-manylinux_x86_64")
|
||||||
|
|
||||||
|
|
||||||
def test_skip():
|
def test_skip():
|
||||||
@@ -144,6 +145,14 @@ def test_build_limited_python_patch():
|
|||||||
assert build_selector("cp37-manylinux_x86_64")
|
assert build_selector("cp37-manylinux_x86_64")
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_free_threaded_python():
|
||||||
|
build_selector = BuildSelector(
|
||||||
|
build_config="*", skip_config="", prerelease_pythons=True, free_threaded_support=True
|
||||||
|
)
|
||||||
|
|
||||||
|
assert build_selector("cp313t-manylinux_x86_64")
|
||||||
|
|
||||||
|
|
||||||
def test_testing_selector():
|
def test_testing_selector():
|
||||||
# local import to avoid pytest trying to collect this as a test class!
|
# local import to avoid pytest trying to collect this as a test class!
|
||||||
from cibuildwheel.util import TestSelector
|
from cibuildwheel.util import TestSelector
|
||||||
|
|||||||
@@ -415,3 +415,36 @@ def test_override_inherit_environment_with_references(tmp_path: Path):
|
|||||||
) == {
|
) == {
|
||||||
"PATH": "/opt/local/bin:/opt/bin:/usr/bin:/bin",
|
"PATH": "/opt/local/bin:/opt/bin:/usr/bin:/bin",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("toml_assignment", "env", "expected_result"),
|
||||||
|
[
|
||||||
|
("", {}, False),
|
||||||
|
("free-threaded-support = true", {}, True),
|
||||||
|
("free-threaded-support = false", {}, False),
|
||||||
|
("", {"CIBW_FREE_THREADED_SUPPORT": "0"}, False),
|
||||||
|
("", {"CIBW_FREE_THREADED_SUPPORT": "1"}, True),
|
||||||
|
("free-threaded-support = false", {"CIBW_FREE_THREADED_SUPPORT": "1"}, True),
|
||||||
|
("free-threaded-support = true", {"CIBW_FREE_THREADED_SUPPORT": "0"}, False),
|
||||||
|
("free-threaded-support = true", {"CIBW_FREE_THREADED_SUPPORT": ""}, True),
|
||||||
|
("free-threaded-support = false", {"CIBW_FREE_THREADED_SUPPORT": ""}, False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_free_threaded_support(
|
||||||
|
tmp_path: Path, toml_assignment: str, env: dict[str, str], expected_result: bool
|
||||||
|
):
|
||||||
|
args = CommandLineArguments.defaults()
|
||||||
|
args.package_dir = tmp_path
|
||||||
|
|
||||||
|
pyproject_toml: Path = tmp_path / "pyproject.toml"
|
||||||
|
pyproject_toml.write_text(
|
||||||
|
textwrap.dedent(
|
||||||
|
f"""\
|
||||||
|
[tool.cibuildwheel]
|
||||||
|
{toml_assignment}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
options = Options(platform="linux", command_line_arguments=args, env=env)
|
||||||
|
assert options.globals.build_selector.free_threaded_support is expected_result
|
||||||
|
|||||||
Reference in New Issue
Block a user