Skip to content

Commit be5fa18

Browse files
committed
feat: add a couple of build commands
Signed-off-by: Henry Schreiner <[email protected]>
1 parent c032a80 commit be5fa18

File tree

7 files changed

+209
-6
lines changed

7 files changed

+209
-6
lines changed

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ known-local-folder = ["pathutils"]
313313
"docs/conf.py" = ["TID251"]
314314
"docs/examples/**" = ["ANN"]
315315
"src/scikit_build_core/file_api/model/*.py" = ["N"]
316+
"**/__main__.py" = ["T20"]
316317

317318

318319
[tool.check-sdist]

src/scikit_build_core/_logging.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -345,17 +345,31 @@ def rich_warning(
345345
color: Literal[
346346
"", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
347347
] = "yellow",
348+
file: object = None,
348349
**kwargs: object,
349350
) -> None:
350-
rich_print("{bold.yellow}WARNING:", *args, color=color, **kwargs) # type: ignore[arg-type]
351+
rich_print(
352+
"{bold.yellow}WARNING:",
353+
*args,
354+
color=color,
355+
file=file or sys.stderr,
356+
**kwargs, # type: ignore[arg-type]
357+
)
351358

352359

353360
def rich_error(
354361
*args: str,
355362
color: Literal[
356363
"", "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
357364
] = "red",
365+
file: object = None,
358366
**kwargs: object,
359367
) -> NoReturn:
360-
rich_print("{bold.red}ERROR:", *args, color=color, **kwargs) # type: ignore[arg-type]
368+
rich_print(
369+
"{bold.red}ERROR:",
370+
*args,
371+
color=color,
372+
file=file or sys.stderr,
373+
**kwargs, # type: ignore[arg-type]
374+
)
361375
raise SystemExit(7)
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import argparse
2+
import json
3+
from pathlib import Path
4+
from typing import Literal
5+
6+
from .._compat import tomllib
7+
from .._logging import rich_warning
8+
from ..builder._load_provider import process_dynamic_metadata
9+
from . import (
10+
get_requires_for_build_editable,
11+
get_requires_for_build_sdist,
12+
get_requires_for_build_wheel,
13+
)
14+
15+
16+
def main_metadata(_args: argparse.Namespace, /) -> None:
17+
"""Get the full metadata, including dynamic metadata."""
18+
with Path("pyproject.toml").open("rb") as f:
19+
pyproject = tomllib.load(f)
20+
21+
project = pyproject.get("project", {})
22+
metadata = pyproject.get("tool", {}).get("scikit-build", {}).get("metadata", {})
23+
new_project = process_dynamic_metadata(project, metadata)
24+
print(json.dumps(new_project, indent=2))
25+
26+
27+
def main_requires(args: argparse.Namespace, /) -> None:
28+
get_requires(args.mode)
29+
30+
31+
def get_requires(mode: Literal["sdist", "wheel", "editable"]) -> None:
32+
"""Get the build requirements."""
33+
34+
with Path("pyproject.toml").open("rb") as f:
35+
pyproject = tomllib.load(f)
36+
37+
requires = pyproject.get("build-system", {}).get("requires", [])
38+
backend = pyproject.get("build-system", {}).get("build-backend", "")
39+
if backend != "scikit_build_core.build":
40+
rich_warning("Might not be a scikit-build-core project.")
41+
if mode == "sdist":
42+
requires += get_requires_for_build_sdist({})
43+
elif mode == "wheel":
44+
requires += get_requires_for_build_wheel({})
45+
elif mode == "editable":
46+
requires += get_requires_for_build_editable({})
47+
print(json.dumps(sorted(set(requires)), indent=2))
48+
49+
50+
def main() -> None:
51+
parser = argparse.ArgumentParser(
52+
description="Build backend utilities",
53+
)
54+
55+
subparsers = parser.add_subparsers(help="Commands")
56+
requires = subparsers.add_parser(
57+
"requires",
58+
help="Get the build requirements",
59+
description="Includes the static build requirements, the dynamically generated ones, and dynamic-metadata ones.",
60+
)
61+
requires.set_defaults(func=main_requires)
62+
requires.add_argument(
63+
"--mode",
64+
choices=["sdist", "wheel", "editable"],
65+
default="wheel",
66+
help="The build mode to get the requirements for",
67+
)
68+
metadata = subparsers.add_parser(
69+
"metadata",
70+
help="Get the full metadata, including dynamic metadata",
71+
description="Processes static and dynamic metadata without triggering the backend, only handles scikit-build-core's dynamic metadata.",
72+
)
73+
metadata.set_defaults(func=main_metadata)
74+
75+
args = parser.parse_args()
76+
args.func(args)
77+
78+
79+
if __name__ == "__main__":
80+
main()

tests/test_broken_fallback.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ def test_fail_setting(
5050
build_wheel("dist")
5151

5252
assert exc.value.code == 7
53-
out, _ = capsys.readouterr()
54-
assert "fail setting was enabled" in out
53+
_, err = capsys.readouterr()
54+
assert "fail setting was enabled" in err
5555

5656

5757
@pytest.mark.usefixtures("broken_fallback")

tests/test_build_cli.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from __future__ import annotations
2+
3+
import json
4+
import shutil
5+
import sys
6+
import sysconfig
7+
from typing import TYPE_CHECKING
8+
9+
import pytest
10+
11+
from scikit_build_core._logging import rich_warning
12+
from scikit_build_core.build.__main__ import main
13+
14+
if TYPE_CHECKING:
15+
from pathlib import Path
16+
17+
PYPROJECT_1 = """
18+
[build-system]
19+
requires = ["scikit-build-core"]
20+
build-backend = "scikit_build_core.build"
21+
[project]
22+
name = "test"
23+
dynamic = ["version"]
24+
25+
[tool.scikit-build.metadata.version]
26+
provider = "scikit_build_core.metadata.setuptools_scm"
27+
"""
28+
29+
30+
@pytest.mark.parametrize("mode", ["sdist", "wheel", "editable"])
31+
def test_requires_command(
32+
capsys: pytest.CaptureFixture[str],
33+
monkeypatch: pytest.MonkeyPatch,
34+
tmp_path: Path,
35+
mode: str,
36+
) -> None:
37+
monkeypatch.setattr(
38+
sys, "argv", ["scikit_build_core.build", "requires", f"--mode={mode}"]
39+
)
40+
monkeypatch.setattr(shutil, "which", lambda _: None)
41+
(tmp_path / "pyproject.toml").write_text(PYPROJECT_1)
42+
monkeypatch.chdir(tmp_path)
43+
44+
main()
45+
rich_warning.cache_clear()
46+
out, err = capsys.readouterr()
47+
assert "CMakeLists.txt not found" in err
48+
jout = json.loads(out)
49+
if mode == "sdist":
50+
assert frozenset(jout) == {"scikit-build-core", "setuptools-scm"}
51+
elif sysconfig.get_platform().startswith("win-"):
52+
assert frozenset(jout) == {
53+
"cmake>=3.15",
54+
"scikit-build-core",
55+
"setuptools-scm",
56+
}
57+
else:
58+
assert frozenset(jout) == {
59+
"cmake>=3.15",
60+
"ninja>=1.5",
61+
"scikit-build-core",
62+
"setuptools-scm",
63+
}
64+
65+
66+
PYPROJECT_2 = """
67+
[build-system]
68+
requires = ["scikit-build-core"]
69+
build-backend = "scikit_build_core.build"
70+
[project]
71+
name = "test"
72+
dynamic = ["version", "dependencies"]
73+
74+
[tool.scikit-build.metadata.version]
75+
provider = "scikit_build_core.metadata.regex"
76+
input = "version.py"
77+
78+
[tool.scikit-build.metadata.dependencies]
79+
provider = "scikit_build_core.metadata.template"
80+
result = ["self=={project[version]}"]
81+
"""
82+
83+
84+
def test_metadata_command(
85+
capsys: pytest.CaptureFixture[str], monkeypatch: pytest.MonkeyPatch, tmp_path: Path
86+
) -> None:
87+
monkeypatch.setattr(sys, "argv", ["scikit_build_core.build", "metadata"])
88+
monkeypatch.setattr(shutil, "which", lambda _: None)
89+
(tmp_path / "pyproject.toml").write_text(PYPROJECT_2)
90+
(tmp_path / "version.py").write_text("version = '0.1.3'")
91+
monkeypatch.chdir(tmp_path)
92+
93+
main()
94+
out, _ = capsys.readouterr()
95+
jout = json.loads(out)
96+
assert jout == {
97+
"name": "test",
98+
"version": "0.1.3",
99+
"dynamic": [],
100+
"dependencies": ["self==0.1.3"],
101+
}

tests/test_printouts.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING
4+
15
from scikit_build_core.builder.__main__ import main
26

7+
if TYPE_CHECKING:
8+
import pytest
9+
310

4-
def test_builder_printout(capsys):
11+
def test_builder_printout(capsys: pytest.CaptureFixture[str]) -> None:
512
main()
613
out, err = capsys.readouterr()
714
assert "Detected Python Library" in out

tests/test_skbuild_settings.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,7 @@ def test_skbuild_settings_auto_cmake_warning(
746746

747747
assert settings_reader.settings.cmake.version == SpecifierSet(">=3.15")
748748

749-
ex = capsys.readouterr().out
749+
ex = capsys.readouterr().err
750750
ex = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", ex)
751751
print(ex)
752752
assert ex.split() == [

0 commit comments

Comments
 (0)