Skip to content

Commit

Permalink
feat: add if.state to overrides (#600)
Browse files Browse the repository at this point in the history
This is the easier of the two suggestions in #591.

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
  • Loading branch information
henryiii committed Jan 3, 2024
1 parent 35821bf commit ec41578
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 34 deletions.
4 changes: 3 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ experimental = true

Scikit-build-core has an override system, similar to cibuildwheel and mypy. You
specify a `tool.scikit-build.overrides` array with an `if` key. That if key can
take several values, based on [PEP 508][]:
take several values, including several based on [PEP 508][]:

- `python-version`: The two-digit Python version. Takes a specifier set.
- `platform-system`: The value of `sys.platform`. Takes a regex.
Expand All @@ -637,6 +637,8 @@ take several values, based on [PEP 508][]:
- `env`: A table of environment variables mapped to either string regexs, or
booleans. Valid "truthy" environment variables are case insensitive `true`,
`on`, `yes`, `y`, `t`, or a number more than 0.
- `state`: The state of the build, one of `sdist`, `wheel`, `editable`,
`metadata_wheel`, and `metadata_editable`. Takes a regex.

At least one must be provided. Then you can specify any collection of valid
options, and those will override if all the items in the `if` are true. They
Expand Down
2 changes: 1 addition & 1 deletion src/scikit_build_core/build/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def build_sdist(
with Path("pyproject.toml").open("rb") as f:
pyproject = tomllib.load(f)

settings_reader = SettingsReader(pyproject, config_settings or {})
settings_reader = SettingsReader(pyproject, config_settings or {}, state="sdist")
settings = settings_reader.settings
setup_logging(settings.logging.level)

Expand Down
18 changes: 10 additions & 8 deletions src/scikit_build_core/build/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from .. import __version__
from .._compat import tomllib
from .._compat.typing import assert_never
from .._compat.typing import Literal, assert_never
from .._logging import logger, rich_print
from .._shutil import fix_win_37_all_permissions
from ..builder.builder import Builder, archs_to_tags, get_archs
Expand Down Expand Up @@ -121,11 +121,19 @@ def _build_wheel_impl(
"""
Build a wheel or just prepare metadata (if wheel dir is None). Can be editable.
"""
state: Literal["sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"]
if exit_after_config:
state = "sdist"
elif wheel_directory is None:
state = "metadata_editable" if editable else "metadata_wheel"
else:
state = "editable" if editable else "wheel"

pyproject_path = Path("pyproject.toml")
with pyproject_path.open("rb") as ft:
pyproject = tomllib.load(ft)

settings_reader = SettingsReader(pyproject, config_settings or {})
settings_reader = SettingsReader(pyproject, config_settings or {}, state=state)
settings = settings_reader.settings
setup_logging(settings.logging.level)

Expand All @@ -139,12 +147,6 @@ def _build_wheel_impl(

normalized_name = metadata.name.replace("-", "_").replace(".", "_")

state = "editable" if editable else "wheel"
if wheel_directory is None:
state = f"metadata_{state}"
if exit_after_config:
state = "sdist"

if settings.wheel.cmake:
cmake = CMake.default_search(minimum_version=settings.cmake.minimum_version)
cmake_msg = [f"using [blue]CMake {cmake.version}[/blue]"]
Expand Down
26 changes: 19 additions & 7 deletions src/scikit_build_core/resources/scikit-build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@
},
"overrides": {
"type": "array",
"description": "A list of overrides to apply to the settings, based on the `if` selector.",
"items": {
"type": "object",
"required": [
Expand Down Expand Up @@ -457,22 +458,32 @@
"additionalProperties": false,
"properties": {
"python-version": {
"type": "string"
"type": "string",
"description": "The two-digit Python version. Takes a specifier set."
},
"implementation-name": {
"type": "string"
"type": "string",
"description": "The value of `sys.implementation.name`. Takes a regex"
},
"implementation-version": {
"type": "string"
"type": "string",
"description": "Derived from `sys.implementation.version`, following PEP 508. Takes a specifier set."
},
"platform-system": {
"type": "string"
"type": "string",
"description": "The value of `sys.platform`. Takes a regex."
},
"platform-machine": {
"type": "string"
"type": "string",
"description": "The value of `platform.machine()`. Takes a regex."
},
"platform-node": {
"type": "string"
"type": "string",
"description": "The value of `platform.node()`. Takes a regex."
},
"state": {
"type": "string",
"description": "The state of the build, one of `sdist`, `wheel`, `editable`, `metadata_wheel`, and `metadata_editable`. Takes a regex."
},
"env": {
"type": "object",
Expand All @@ -489,7 +500,8 @@
}
},
"additionalProperties": false,
"minProperties": 1
"minProperties": 1,
"description": "A table of environment variables mapped to either string regexs, or booleans. Valid 'truthy' environment variables are case insensitive `true`, `on`, `yes`, `y`, `t`, or a number more than 0."
}
}
}
Expand Down
26 changes: 23 additions & 3 deletions src/scikit_build_core/settings/skbuild_read_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
if TYPE_CHECKING:
from collections.abc import Generator, Mapping

from .._compat.typing import Literal

__all__ = ["SettingsReader"]


Expand Down Expand Up @@ -60,13 +62,17 @@ def override_match(
*,
match_all: bool,
current_env: Mapping[str, str] | None,
current_state: Literal[
"sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"
],
python_version: str | None = None,
implementation_name: str | None = None,
implementation_version: str | None = None,
platform_system: str | None = None,
platform_machine: str | None = None,
platform_node: str | None = None,
env: dict[str, str] | None = None,
state: str | None = None,
) -> bool:
matches = []
if current_env is None:
Expand Down Expand Up @@ -108,6 +114,10 @@ def override_match(
match_msg = regex_match(current_platform_node, platform_node)
matches.append(match_msg)

if state is not None:
match_msg = regex_match(current_state, state)
matches.append(match_msg)

if env:
for key, value in env.items():
if isinstance(value, bool):
Expand Down Expand Up @@ -144,6 +154,9 @@ def __init__(
pyproject: dict[str, Any],
config_settings: Mapping[str, str | list[str]],
*,
state: Literal[
"sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"
],
verify_conf: bool = True,
env: Mapping[str, str] | None = None,
) -> None:
Expand All @@ -163,11 +176,13 @@ def __init__(
if "any" in if_override:
any_override = if_override.pop("any")
select = {k.replace("-", "_"): v for k, v in any_override.items()}
matched = override_match(match_all=False, current_env=env, **select)
matched = override_match(
match_all=False, current_env=env, current_state=state, **select
)
select = {k.replace("-", "_"): v for k, v in if_override.items()}
if select:
matched = matched and override_match(
match_all=True, current_env=env, **select
match_all=True, current_env=env, current_state=state, **select
)
if matched:
for key, value in override.items():
Expand Down Expand Up @@ -301,9 +316,14 @@ def from_file(
pyproject_path: os.PathLike[str] | str,
config_settings: Mapping[str, str | list[str]] | None,
*,
state: Literal[
"sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"
] = "sdist",
verify_conf: bool = True,
) -> SettingsReader:
with Path(pyproject_path).open("rb") as f:
pyproject = tomllib.load(f)

return cls(pyproject, config_settings or {}, verify_conf=verify_conf)
return cls(
pyproject, config_settings or {}, verify_conf=verify_conf, state=state
)
36 changes: 30 additions & 6 deletions src/scikit_build_core/settings/skbuild_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,48 @@ def generate_skbuild_schema(tool_name: str = "scikit-build") -> dict[str, Any]:
"minProperties": 1,
"additionalProperties": False,
"properties": {
"python-version": {"type": "string"},
"implementation-name": {"type": "string"},
"implementation-version": {"type": "string"},
"platform-system": {"type": "string"},
"platform-machine": {"type": "string"},
"platform-node": {"type": "string"},
"python-version": {
"type": "string",
"description": "The two-digit Python version. Takes a specifier set.",
},
"implementation-name": {
"type": "string",
"description": "The value of `sys.implementation.name`. Takes a regex",
},
"implementation-version": {
"type": "string",
"description": "Derived from `sys.implementation.version`, following PEP 508. Takes a specifier set.",
},
"platform-system": {
"type": "string",
"description": "The value of `sys.platform`. Takes a regex.",
},
"platform-machine": {
"type": "string",
"description": "The value of `platform.machine()`. Takes a regex.",
},
"platform-node": {
"type": "string",
"description": "The value of `platform.node()`. Takes a regex.",
},
"state": {
"type": "string",
"description": "The state of the build, one of `sdist`, `wheel`, `editable`, `metadata_wheel`, and `metadata_editable`. Takes a regex.",
},
"env": {
"type": "object",
"patternProperties": {
".*": {"oneOf": [{"type": "string"}, {"type": "boolean"}]}
},
"additionalProperties": False,
"minProperties": 1,
"description": "A table of environment variables mapped to either string regexs, or booleans. Valid 'truthy' environment variables are case insensitive `true`, `on`, `yes`, `y`, `t`, or a number more than 0.",
},
},
}
schema["properties"]["overrides"] = {
"type": "array",
"description": "A list of overrides to apply to the settings, based on the `if` selector.",
"items": {
"type": "object",
"required": ["if"],
Expand Down
18 changes: 10 additions & 8 deletions tests/test_dynamic_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def mock_entry_points(monkeypatch):
def test_dynamic_metadata():
with Path("pyproject.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_plugin_metadata():

with Path("pyproject.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand All @@ -153,7 +153,7 @@ def test_plugin_metadata():
def test_faulty_metadata():
with Path("faulty_project.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand All @@ -166,7 +166,7 @@ def test_faulty_metadata():
def test_local_plugin_metadata():
with Path("local_pyproject.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand All @@ -179,7 +179,7 @@ def test_local_plugin_metadata():
def test_warn_metadata():
with Path("warn_project.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand All @@ -192,7 +192,9 @@ def test_warn_metadata():
def test_fail_experimental_metadata():
with Path("warn_project.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {"experimental": "false"})
settings_reader = SettingsReader(
pyproject, {"experimental": "false"}, state="metadata_wheel"
)

with pytest.raises(SystemExit) as exc:
settings_reader.validate_may_exit()
Expand All @@ -204,7 +206,7 @@ def test_fail_experimental_metadata():
def test_dual_metadata():
with Path("dual_project.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand All @@ -215,7 +217,7 @@ def test_dual_metadata():

with Path("faulty_dual_project.toml").open("rb") as ft:
pyproject = tomllib.load(ft)
settings_reader = SettingsReader(pyproject, {})
settings_reader = SettingsReader(pyproject, {}, state="metadata_wheel")
settings = settings_reader.settings

settings_reader.validate_may_exit()
Expand Down
23 changes: 23 additions & 0 deletions tests/test_settings_overrides.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,26 @@ def test_skbuild_env_bool_all_any(
assert settings.sdist.cmake
else:
assert not settings.sdist.cmake


@pytest.mark.parametrize("state", ["wheel", "sdist"])
def test_skbuild_overrides_state(state: str, tmp_path: Path):
pyproject_toml = tmp_path / "pyproject.toml"
pyproject_toml.write_text(
dedent(
f"""\
[[tool.scikit-build.overrides]]
if.state = "{state}"
experimental = true
"""
),
encoding="utf-8",
)

settings_reader = SettingsReader.from_file(pyproject_toml, {}, state="wheel")
settings = settings_reader.settings

if state == "wheel":
assert settings.experimental
else:
assert not settings.experimental

0 comments on commit ec41578

Please sign in to comment.