Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding enable #2048

Merged
merged 4 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions bin/generate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
- append
default: none
description: How to inherit the parent's value.
enable:
enum:
- cpython-freethreading
- cpython-prerelease
- pypy
description: A Python version or flavor to enable.
additionalProperties: false
description: cibuildwheel's settings.
type: object
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -261,6 +275,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()
Expand Down
60 changes: 47 additions & 13 deletions cibuildwheel/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
BuildFrontendConfig,
BuildSelector,
DependencyConstraints,
EnableGroups,
TestSelector,
format_safe,
read_python_configs,
resources_dir,
selector_matches,
strtobool,
Expand Down Expand Up @@ -512,6 +514,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,
Expand Down Expand Up @@ -543,8 +546,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,
)
Expand All @@ -558,14 +561,15 @@ def __init__(
platform: PlatformName,
command_line_arguments: CommandLineArguments,
env: Mapping[str, str],
read_config_file: bool = True,
defaults: bool = False,
):
self.platform = platform
self.command_line_arguments = command_line_arguments
self.env = env
self._defaults = defaults

self.reader = OptionsReader(
self.config_file_path if read_config_file else None,
None if defaults else self.config_file_path,
platform=platform,
env=env,
disallow=DISALLOWED_OPTIONS,
Expand All @@ -578,7 +582,7 @@ def __init__(
except FileNotFoundError:
self.pyproject_toml = None

@property
@functools.cached_property
def config_file_path(self) -> Path | None:
args = self.command_line_arguments

Expand All @@ -596,7 +600,7 @@ def config_file_path(self) -> Path | None:
def package_requires_python_str(self) -> str | None:
return get_requires_python_str(self.package_dir, self.pyproject_toml)

@property
@functools.cached_property
def globals(self) -> GlobalOptions:
args = self.command_line_arguments
package_dir = args.package_dir
Expand All @@ -608,16 +612,34 @@ 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.CPythonFreeThreading)
if prerelease_pythons:
enable.add(EnableGroups.CPythonPrerelease)

# 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 = (
Expand All @@ -633,18 +655,30 @@ 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 | {EnableGroups.PyPy}
), # For backwards compatibility, we are adding PyPy for now
)
test_selector = TestSelector(skip_config=test_skip)

all_configs = read_python_configs(self.platform)
all_pypy_ids = {
config["identifier"] for config in all_configs if config["identifier"].startswith("pp")
}
if (
not self._defaults
and EnableGroups.PyPy not in enable
and any(build_selector(build_id) for build_id in all_pypy_ids)
):
msg = "PyPy builds will be disabled by default in version 3. Enabling PyPy builds should be specified by enable"
log.warning(msg)

return GlobalOptions(
package_dir=package_dir,
output_dir=output_dir,
Expand Down Expand Up @@ -831,7 +865,7 @@ def defaults(self) -> Options:
platform=self.platform,
command_line_arguments=CommandLineArguments.defaults(),
env={},
read_config_file=False,
defaults=True,
)

def summary(self, identifiers: Iterable[str]) -> str:
Expand Down
26 changes: 25 additions & 1 deletion cibuildwheel/resources/cibuildwheel.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@
],
"default": "none",
"description": "How to inherit the parent's value."
}
},
"enable": {
"enum": [
"cpython-eol",
"cpython-freethreading",
"cpython-prerelease",
"pypy-eol"
]
},
"description": "A Python version or flavor to enable."
},
"additionalProperties": false,
"description": "cibuildwheel's settings.",
Expand Down Expand Up @@ -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": [
Expand Down
1 change: 1 addition & 0 deletions cibuildwheel/resources/defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ build = "*"
skip = ""
test-skip = ""
free-threaded-support = false
enable = []

archs = ["auto"]
build-frontend = "default"
Expand Down
38 changes: 24 additions & 14 deletions cibuildwheel/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import contextlib
import enum
import fnmatch
import itertools
import os
Expand All @@ -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
Expand All @@ -41,6 +42,7 @@

__all__ = [
"MANYLINUX_ARCHS",
"EnableGroups",
"call",
"chdir",
"combine_constraints",
Expand All @@ -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.
"""

CPythonFreeThreading = "cpython-freethreading"
CPythonPrerelease = "cpython-prerelease"
PyPy = "pypy"


MANYLINUX_ARCHS: Final[tuple[str, ...]] = (
"x86_64",
"i686",
Expand Down Expand Up @@ -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
Expand All @@ -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.CPythonFreeThreading 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)
Expand All @@ -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),
}


Expand Down
Loading
Loading