Files
cibuildwheel/cibuildwheel/frontend.py
T

85 lines
2.6 KiB
Python
Raw Normal View History

import dataclasses
2025-01-27 20:35:56 +01:00
import shlex
import typing
from collections.abc import Sequence
from typing import Literal, Self, get_args
2025-01-27 20:35:56 +01:00
from .logger import log
from .util.helpers import parse_key_value_string
BuildFrontendName = Literal["pip", "build", "build[uv]"]
@dataclasses.dataclass(frozen=True)
2025-01-27 20:35:56 +01:00
class BuildFrontendConfig:
name: BuildFrontendName
args: Sequence[str] = ()
@classmethod
def from_config_string(cls, config_string: str) -> Self:
2025-01-27 20:35:56 +01:00
config_dict = parse_key_value_string(config_string, ["name"], ["args"])
name = " ".join(config_dict["name"])
2025-02-12 12:41:44 -05:00
if name not in get_args(BuildFrontendName):
names = ", ".join(repr(n) for n in get_args(BuildFrontendName))
msg = f"Unrecognised build frontend {name!r}, must be one of {names}"
2025-01-27 20:35:56 +01:00
raise ValueError(msg)
name = typing.cast(BuildFrontendName, name)
args = config_dict.get("args") or []
return cls(name=name, args=args)
2025-01-27 20:35:56 +01:00
def options_summary(self) -> str | dict[str, str]:
if not self.args:
return self.name
else:
return {"name": self.name, "args": repr(self.args)}
def _get_verbosity_flags(level: int, frontend: BuildFrontendName) -> list[str]:
if level < 0:
if frontend == "pip":
2025-01-27 20:35:56 +01:00
return ["-" + -level * "q"]
2025-02-12 12:41:44 -05:00
msg = f"build_verbosity {level} is not supported for {frontend} frontend. Ignoring."
2025-01-27 20:35:56 +01:00
log.warning(msg)
if level > 0:
if frontend == "pip":
return ["-" + level * "v"]
if level > 1:
return ["-" + (level - 1) * "v"]
2025-01-27 20:35:56 +01:00
return []
2025-02-12 12:41:44 -05:00
def _split_config_settings(config_settings: str) -> list[str]:
2025-01-27 20:35:56 +01:00
config_settings_list = shlex.split(config_settings)
2025-02-12 12:41:44 -05:00
return [f"-C{setting}" for setting in config_settings_list]
2025-01-27 20:35:56 +01:00
# Based on build.__main__.main.
def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str]]:
config_settings: dict[str, str | list[str]] = {}
for arg in shlex.split(config_settings_str):
setting, _, value = arg.partition("=")
existing_value = config_settings.get(setting)
if existing_value is None:
config_settings[setting] = value
elif isinstance(existing_value, str):
config_settings[setting] = [existing_value, value]
else:
existing_value.append(value)
return config_settings
2025-01-27 20:35:56 +01:00
def get_build_frontend_extra_flags(
build_frontend: BuildFrontendConfig, verbosity_level: int, config_settings: str
) -> list[str]:
return [
2025-02-12 12:41:44 -05:00
*_split_config_settings(config_settings),
2025-01-27 20:35:56 +01:00
*build_frontend.args,
*_get_verbosity_flags(verbosity_level, build_frontend.name),
]