Repository: scikit-build/scikit-build-core (python)

Issue:
Renames now that we have a build section
I'd like to rename:

* `cmake.targets` -> `build.targets`
* `cmake.verbose` -> `build.verbose`

Old will work but be deprecated (minimum-version based).

Pull request:
feat: move some cmake options to build section
Fix #747.


Patch:
diff --git a/README.md b/README.md
index d83b0f6..ba3df10 100644
--- a/README.md
+++ b/README.md
@@ -164,8 +164,8 @@ cmake.args = []
 # A table of defines to pass to CMake when configuring the project. Additive.
 cmake.define = {}
 
-# Verbose printout when building.
-cmake.verbose = false
+# DEPRECATED in 0.10, use build.verbose instead.
+cmake.verbose = ""
 
 # The build type to use when building the project. Valid options are: "Debug",
 # "Release", "RelWithDebInfo", "MinSizeRel", "", etc.
@@ -175,9 +175,8 @@ cmake.build-type = "Release"
 # the native builder (not the setuptools plugin).
 cmake.source-dir = "."
 
-# The build targets to use when building the project. Empty builds the default
-# target.
-cmake.targets = []
+# DEPRECATED in 0.10; use build.targets instead.
+cmake.targets = ""
 
 # The versions of Ninja to allow. If Ninja is not present on the system or does
 # not pass this specifier, it will be downloaded via PyPI if possible. An empty
@@ -269,6 +268,13 @@ editable.rebuild = false
 # Extra args to pass directly to the builder in the build step.
 build.tool-args = []
 
+# The build targets to use when building the project. Empty builds the default
+# target.
+build.targets = []
+
+# Verbose printout when building.
+build.verbose = false
+
 # The components to install. If empty, all default components are installed.
 install.components = []
 
diff --git a/docs/projects.md b/docs/projects.md
index 5258c73..3e3ce6a 100644
--- a/docs/projects.md
+++ b/docs/projects.md
@@ -52,4 +52,4 @@ In addition, most of the [RAPIDSAI](https://github.com/rapidsai) projects use sc
 * CuML ([source](https://github.com/rapidsai/cuml/blob/HEAD/python/pyproject.toml))
 * CuSpatial ([source](https://github.com/rapidsai/cuspatial/blob/HEAD/python/cuspatial/pyproject.toml))
 * RMM ([source](https://github.com/rapidsai/rmm/blob/HEAD/python/rmm/pyproject.toml))
-* Raft[source](https://github.com/rapidsai/raft/blob/HEAD/python/pylibraft/pyproject.toml))
+* Raft ([source](https://github.com/rapidsai/raft/blob/HEAD/python/pylibraft/pyproject.toml))
diff --git a/src/scikit_build_core/builder/builder.py b/src/scikit_build_core/builder/builder.py
index 43a0cc6..fbf5a1b 100644
--- a/src/scikit_build_core/builder/builder.py
+++ b/src/scikit_build_core/builder/builder.py
@@ -244,8 +244,8 @@ class Builder:
 
         self.config.build(
             build_args=build_args,
-            targets=self.settings.cmake.targets,
-            verbose=self.settings.cmake.verbose,
+            targets=self.settings.build.targets,
+            verbose=self.settings.build.verbose,
         )
 
     def install(self, install_dir: Path | None) -> None:
diff --git a/src/scikit_build_core/resources/scikit-build.schema.json b/src/scikit_build_core/resources/scikit-build.schema.json
index d4dfb8e..25459ce 100644
--- a/src/scikit_build_core/resources/scikit-build.schema.json
+++ b/src/scikit_build_core/resources/scikit-build.schema.json
@@ -71,8 +71,8 @@
         },
         "verbose": {
           "type": "boolean",
-          "default": false,
-          "description": "Verbose printout when building."
+          "description": "DEPRECATED in 0.10, use build.verbose instead.",
+          "deprecated": true
         },
         "build-type": {
           "type": "string",
@@ -89,7 +89,8 @@
           "items": {
             "type": "string"
           },
-          "description": "The build targets to use when building the project. Empty builds the default target."
+          "description": "DEPRECATED in 0.10; use build.targets instead.",
+          "deprecated": true
         }
       }
     },
@@ -263,6 +264,18 @@
             "type": "string"
           },
           "description": "Extra args to pass directly to the builder in the build step."
+        },
+        "targets": {
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "description": "The build targets to use when building the project. Empty builds the default target."
+        },
+        "verbose": {
+          "type": "boolean",
+          "default": false,
+          "description": "Verbose printout when building."
         }
       }
     },
@@ -500,6 +513,9 @@
                 "properties": {
                   "tool-args": {
                     "$ref": "#/$defs/inherit"
+                  },
+                  "targets": {
+                    "$ref": "#/$defs/inherit"
                   }
                 }
               },
diff --git a/src/scikit_build_core/settings/skbuild_model.py b/src/scikit_build_core/settings/skbuild_model.py
index bc52a42..4dd4c81 100644
--- a/src/scikit_build_core/settings/skbuild_model.py
+++ b/src/scikit_build_core/settings/skbuild_model.py
@@ -53,9 +53,9 @@ class CMakeSettings:
     A table of defines to pass to CMake when configuring the project. Additive.
     """
 
-    verbose: bool = False
+    verbose: Optional[bool] = None
     """
-    Verbose printout when building.
+    DEPRECATED in 0.10, use build.verbose instead.
     """
 
     build_type: str = "Release"
@@ -71,10 +71,9 @@ class CMakeSettings:
     affects the native builder (not the setuptools plugin).
     """
 
-    targets: List[str] = dataclasses.field(default_factory=list)
+    targets: Optional[List[str]] = None
     """
-    The build targets to use when building the project. Empty builds the
-    default target.
+    DEPRECATED in 0.10; use build.targets instead.
     """
 
 
@@ -240,6 +239,17 @@ class BuildSettings:
     Extra args to pass directly to the builder in the build step.
     """
 
+    targets: List[str] = dataclasses.field(default_factory=list)
+    """
+    The build targets to use when building the project. Empty builds the
+    default target.
+    """
+
+    verbose: bool = False
+    """
+    Verbose printout when building.
+    """
+
 
 @dataclasses.dataclass
 class InstallSettings:
diff --git a/src/scikit_build_core/settings/skbuild_read_settings.py b/src/scikit_build_core/settings/skbuild_read_settings.py
index 3da3a3a..6ca0013 100644
--- a/src/scikit_build_core/settings/skbuild_read_settings.py
+++ b/src/scikit_build_core/settings/skbuild_read_settings.py
@@ -8,7 +8,7 @@ import platform
 import re
 import sys
 from pathlib import Path
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, TypeVar
 
 from packaging.specifiers import SpecifierSet
 from packaging.version import Version
@@ -32,6 +32,9 @@ def __dir__() -> list[str]:
     return __all__
 
 
+T = TypeVar("T")
+
+
 def strtobool(value: str) -> bool:
     """
     Converts a environment variable string into a boolean value.
@@ -191,6 +194,51 @@ def _handle_minimum_version(
         dc.version = SpecifierSet(f">={dc.minimum_version}")
 
 
+def _handle_move(
+    before_name: str,
+    before: T | None,
+    after_name: str,
+    after: T,
+    minimum_version: Version | None,
+    introduced_in: Version,
+) -> T:
+    """
+    Backward_compat for moving names around. The default must be false-like.
+    """
+
+    if after and minimum_version is not None and minimum_version < introduced_in:
+        rich_print(
+            f"[red][bold]ERROR:[/bold] Cannot set {after_name} if minimum-version is set to less than {introduced_in} (which is where it was introduced)"
+        )
+        raise SystemExit(7)
+
+    if (
+        before is not None
+        and minimum_version is not None
+        and minimum_version >= introduced_in
+    ):
+        rich_print(
+            f"[red][bold]ERROR:[/bold] Cannot set {before_name} if minimum-version is set to {introduced_in} or higher"
+        )
+        raise SystemExit(7)
+
+    if before is not None and after:
+        rich_print(
+            f"[red][bold]ERROR:[/bold] Cannot set {before_name} and {after_name} at the same time"
+        )
+        raise SystemExit(7)
+
+    if before is None:
+        return after
+
+    if minimum_version is None:
+        rich_print(
+            f"[yellow][bold]WARNING:[/bold] Use {after_name} instead of {before_name} for scikit-build-core >= {introduced_in}"
+        )
+
+    return before
+
+
 def inherit_join(
     value: list[str] | dict[str, str] | str | int | bool,
     previous: list[str] | dict[str, str] | str | int | bool | None,
@@ -336,6 +384,23 @@ class SettingsReader:
         _handle_minimum_version(self.settings.cmake, self.settings.minimum_version)
         _handle_minimum_version(self.settings.ninja, self.settings.minimum_version)
 
+        self.settings.build.verbose = _handle_move(
+            "cmake.verbose",
+            self.settings.cmake.verbose,
+            "build.verbose",
+            self.settings.build.verbose,
+            self.settings.minimum_version,
+            Version("0.10"),
+        )
+        self.settings.build.targets = _handle_move(
+            "cmake.targets",
+            self.settings.cmake.targets,
+            "build.targets",
+            self.settings.build.targets,
+            self.settings.minimum_version,
+            Version("0.10"),
+        )
+
     def unrecognized_options(self) -> Generator[str, None, None]:
         return self.sources.unrecognized_options(ScikitBuildSettings)
 


Test patch:
diff --git a/tests/test_builder.py b/tests/test_builder.py
index 05a1756..890d906 100644
--- a/tests/test_builder.py
+++ b/tests/test_builder.py
@@ -142,7 +142,7 @@ def test_build_tool_args():
     )
     tmpbuilder.build(["a"])
     config.build.assert_called_once_with(
-        build_args=["a", "--", "b"], targets=[], verbose=settings.cmake.verbose
+        build_args=["a", "--", "b"], targets=[], verbose=settings.build.verbose
     )
 
 
diff --git a/tests/test_skbuild_settings.py b/tests/test_skbuild_settings.py
index 6d84306..5cb9025 100644
--- a/tests/test_skbuild_settings.py
+++ b/tests/test_skbuild_settings.py
@@ -33,10 +33,10 @@ def test_skbuild_settings_default(tmp_path: Path):
     assert settings.cmake.version == SpecifierSet(">=3.15")
     assert settings.cmake.args == []
     assert settings.cmake.define == {}
-    assert not settings.cmake.verbose
+    assert not settings.build.verbose
     assert settings.cmake.build_type == "Release"
     assert settings.cmake.source_dir == Path()
-    assert settings.cmake.targets == []
+    assert settings.build.targets == []
     assert settings.logging.level == "WARNING"
     assert settings.sdist.include == []
     assert settings.sdist.exclude == []
@@ -70,17 +70,16 @@ def test_skbuild_settings_default(tmp_path: Path):
 
 def test_skbuild_settings_envvar(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
     monkeypatch.setattr(
-        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.1.0"
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
     )
 
-    monkeypatch.setenv("SKBUILD_NINJA_MINIMUM_VERSION", "1.1")
+    monkeypatch.setenv("SKBUILD_NINJA_VERSION", ">=1.1")
     monkeypatch.setenv("SKBUILD_NINJA_MAKE_FALLBACK", "0")
-    monkeypatch.setenv("SKBUILD_CMAKE_MINIMUM_VERSION", "3.16")
+    monkeypatch.setenv("SKBUILD_CMAKE_VERSION", ">=3.16")
     monkeypatch.setenv("SKBUILD_CMAKE_ARGS", "-DFOO=BAR;-DBAR=FOO")
     monkeypatch.setenv("SKBUILD_CMAKE_DEFINE", "a=1;b=2")
     monkeypatch.setenv("SKBUILD_CMAKE_BUILD_TYPE", "Debug")
     monkeypatch.setenv("SKBUILD_CMAKE_SOURCE_DIR", "a/b/c")
-    monkeypatch.setenv("SKBUILD_CMAKE_TARGETS", "a;b;c")
     monkeypatch.setenv("SKBUILD_LOGGING_LEVEL", "DEBUG")
     monkeypatch.setenv("SKBUILD_SDIST_INCLUDE", "a;b; c")
     monkeypatch.setenv("SKBUILD_SDIST_EXCLUDE", "d;e;f")
@@ -95,11 +94,12 @@ def test_skbuild_settings_envvar(tmp_path: Path, monkeypatch: pytest.MonkeyPatch
     monkeypatch.setenv("SKBUILD_BACKPORT_FIND_PYTHON", "0")
     monkeypatch.setenv("SKBUILD_STRICT_CONFIG", "0")
     monkeypatch.setenv("SKBUILD_EXPERIMENTAL", "1")
-    monkeypatch.setenv("SKBUILD_MINIMUM_VERSION", "0.1")
-    monkeypatch.setenv("SKBUILD_CMAKE_VERBOSE", "TRUE")
+    monkeypatch.setenv("SKBUILD_MINIMUM_VERSION", "0.10")
     monkeypatch.setenv("SKBUILD_BUILD_DIR", "a/b/c")
     monkeypatch.setenv("SKBUILD_EDITABLE_REBUILD", "True")
     monkeypatch.setenv("SKBUILD_EDITABLE_VERBOSE", "False")
+    monkeypatch.setenv("SKBUILD_BUILD_VERBOSE", "TRUE")
+    monkeypatch.setenv("SKBUILD_BUILD_TARGETS", "a;b;c")
     monkeypatch.setenv("SKBUILD_BUILD_TOOL_ARGS", "a;b")
     monkeypatch.setenv("SKBUILD_INSTALL_COMPONENTS", "a;b;c")
     monkeypatch.setenv("SKBUILD_INSTALL_STRIP", "False")
@@ -113,14 +113,12 @@ def test_skbuild_settings_envvar(tmp_path: Path, monkeypatch: pytest.MonkeyPatch
     settings = settings_reader.settings
     assert list(settings_reader.unrecognized_options()) == []
 
-    assert settings.ninja.minimum_version == Version("1.1")
-    assert settings.cmake.minimum_version == Version("3.16")
+    assert settings.ninja.version == SpecifierSet(">=1.1")
+    assert settings.cmake.version == SpecifierSet(">=3.16")
     assert settings.cmake.args == ["-DFOO=BAR", "-DBAR=FOO"]
     assert settings.cmake.define == {"a": "1", "b": "2"}
-    assert settings.cmake.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == Path("a/b/c")
-    assert settings.cmake.targets == ["a", "b", "c"]
     assert not settings.ninja.make_fallback
     assert settings.logging.level == "DEBUG"
     assert settings.sdist.include == ["a", "b", "c"]
@@ -136,12 +134,14 @@ def test_skbuild_settings_envvar(tmp_path: Path, monkeypatch: pytest.MonkeyPatch
     assert settings.backport.find_python == Version("0")
     assert not settings.strict_config
     assert settings.experimental
-    assert settings.minimum_version == Version("0.1")
+    assert settings.minimum_version == Version("0.10")
     assert settings.build_dir == "a/b/c"
     assert settings.metadata == {}
     assert settings.editable.mode == "redirect"
     assert settings.editable.rebuild
     assert not settings.editable.verbose
+    assert settings.build.verbose
+    assert settings.build.targets == ["a", "b", "c"]
     assert settings.build.tool_args == ["a", "b"]
     assert settings.install.components == ["a", "b", "c"]
     assert not settings.install.strip
@@ -152,23 +152,21 @@ def test_skbuild_settings_config_settings(
     tmp_path: Path, monkeypatch: pytest.MonkeyPatch, prefix: bool
 ):
     monkeypatch.setattr(
-        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.1.0"
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
     )
 
     pyproject_toml = tmp_path / "pyproject.toml"
     pyproject_toml.write_text("", encoding="utf-8")
 
     config_settings: dict[str, str | list[str]] = {
-        "ninja.minimum-version": "1.2",
+        "ninja.version": ">=1.2",
         "ninja.make-fallback": "False",
-        "cmake.minimum-version": "3.17",
+        "cmake.version": ">=3.17",
         "cmake.args": ["-DFOO=BAR", "-DBAR=FOO"],
         "cmake.define.a": "1",
         "cmake.define.b": "2",
-        "cmake.verbose": "true",
         "cmake.build-type": "Debug",
         "cmake.source-dir": "a/b/c",
-        "cmake.targets": ["a", "b", "c"],
         "logging.level": "INFO",
         "sdist.include": ["a", "b", "c"],
         "sdist.exclude": "d;e;f",
@@ -183,11 +181,13 @@ def test_skbuild_settings_config_settings(
         "backport.find-python": "0",
         "strict-config": "false",
         "experimental": "1",
-        "minimum-version": "0.1",
+        "minimum-version": "0.10",
         "build-dir": "a/b/c",
         "editable.mode": "redirect",
         "editable.rebuild": "True",
         "editable.verbose": "False",
+        "build.verbose": "true",
+        "build.targets": ["a", "b", "c"],
         "build.tool-args": ["a", "b"],
         "install.components": ["a", "b", "c"],
         "install.strip": "True",
@@ -200,15 +200,14 @@ def test_skbuild_settings_config_settings(
     settings = settings_reader.settings
     assert list(settings_reader.unrecognized_options()) == []
 
-    assert settings.ninja.minimum_version == Version("1.2")
+    assert settings.ninja.version == SpecifierSet(">=1.2")
     assert not settings.ninja.make_fallback
-    assert settings.cmake.minimum_version == Version("3.17")
+    assert settings.cmake.version == SpecifierSet(">=3.17")
     assert settings.cmake.args == ["-DFOO=BAR", "-DBAR=FOO"]
     assert settings.cmake.define == {"a": "1", "b": "2"}
-    assert settings.cmake.verbose
+    assert settings.build.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == Path("a/b/c")
-    assert settings.cmake.targets == ["a", "b", "c"]
     assert settings.logging.level == "INFO"
     assert settings.sdist.include == ["a", "b", "c"]
     assert settings.sdist.exclude == ["d", "e", "f"]
@@ -223,12 +222,13 @@ def test_skbuild_settings_config_settings(
     assert settings.backport.find_python == Version("0")
     assert not settings.strict_config
     assert settings.experimental
-    assert settings.minimum_version == Version("0.1")
+    assert settings.minimum_version == Version("0.10")
     assert settings.build_dir == "a/b/c"
     assert settings.metadata == {}
     assert settings.editable.mode == "redirect"
     assert settings.editable.rebuild
     assert not settings.editable.verbose
+    assert settings.build.targets == ["a", "b", "c"]
     assert settings.build.tool_args == ["a", "b"]
     assert settings.install.components == ["a", "b", "c"]
     assert settings.install.strip
@@ -238,22 +238,20 @@ def test_skbuild_settings_pyproject_toml(
     tmp_path: Path, monkeypatch: pytest.MonkeyPatch
 ):
     monkeypatch.setattr(
-        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.1.0"
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
     )
     pyproject_toml = tmp_path / "pyproject.toml"
     pyproject_toml.write_text(
         textwrap.dedent(
             """\
             [tool.scikit-build]
-            ninja.minimum-version = "1.3"
+            ninja.version = ">=1.3"
             ninja.make-fallback = false
-            cmake.minimum-version = "3.18"
+            cmake.version = ">=3.18"
             cmake.args = ["-DFOO=BAR", "-DBAR=FOO"]
             cmake.define = {a = "1", b = "2"}
             cmake.build-type = "Debug"
-            cmake.verbose = true
             cmake.source-dir = "a/b/c"
-            cmake.targets = ["a", "b", "c"]
             logging.level = "ERROR"
             sdist.include = ["a", "b", "c"]
             sdist.exclude = ["d", "e", "f"]
@@ -268,12 +266,14 @@ def test_skbuild_settings_pyproject_toml(
             backport.find-python = "3.18"
             strict-config = false
             experimental = true
-            minimum-version = "0.1"
+            minimum-version = "0.10"
             build-dir = "a/b/c"
             metadata.version.provider = "a"
             editable.mode = "redirect"
             editable.rebuild = true
             editable.verbose = false
+            build.verbose = true
+            build.targets = ["a", "b", "c"]
             build.tool-args = ["a", "b"]
             install.components = ["a", "b", "c"]
             install.strip = true
@@ -295,15 +295,13 @@ def test_skbuild_settings_pyproject_toml(
     settings = settings_reader.settings
     assert list(settings_reader.unrecognized_options()) == []
 
-    assert settings.ninja.minimum_version == Version("1.3")
+    assert settings.ninja.version == SpecifierSet(">=1.3")
     assert not settings.ninja.make_fallback
-    assert settings.cmake.minimum_version == Version("3.18")
+    assert settings.cmake.version == SpecifierSet(">=3.18")
     assert settings.cmake.args == ["-DFOO=BAR", "-DBAR=FOO"]
     assert settings.cmake.define == {"a": "1", "b": "2"}
-    assert settings.cmake.verbose
     assert settings.cmake.build_type == "Debug"
     assert settings.cmake.source_dir == Path("a/b/c")
-    assert settings.cmake.targets == ["a", "b", "c"]
     assert settings.logging.level == "ERROR"
     assert settings.sdist.include == ["a", "b", "c"]
     assert settings.sdist.exclude == ["d", "e", "f"]
@@ -318,12 +316,14 @@ def test_skbuild_settings_pyproject_toml(
     assert settings.backport.find_python == Version("3.18")
     assert not settings.strict_config
     assert settings.experimental
-    assert settings.minimum_version == Version("0.1")
+    assert settings.minimum_version == Version("0.10")
     assert settings.build_dir == "a/b/c"
     assert settings.metadata == {"version": {"provider": "a"}}
     assert settings.editable.mode == "redirect"
     assert settings.editable.rebuild
     assert not settings.editable.verbose
+    assert settings.build.verbose
+    assert settings.build.targets == ["a", "b", "c"]
     assert settings.build.tool_args == ["a", "b"]
     assert settings.install.components == ["a", "b", "c"]
     assert settings.install.strip
@@ -512,3 +512,68 @@ def test_skbuild_settings_pyproject_toml_envvar_defines(
         "d": False,
         "e": True,
     }
+
+
+def test_backcompat_cmake_build(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
+    monkeypatch.setattr(
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
+    )
+    pyproject_toml = tmp_path / "pyproject.toml"
+    pyproject_toml.write_text(
+        textwrap.dedent(
+            """\
+            [tool.scikit-build]
+            minimum-version = "0.9"
+            cmake.verbose = true
+            cmake.targets = ["a", "b"]
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {})
+    assert settings_reader.settings.build.verbose
+    assert settings_reader.settings.build.targets == ["a", "b"]
+
+
+def test_backcompat_cmake_build_env(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
+    monkeypatch.setattr(
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.9.0"
+    )
+    pyproject_toml = tmp_path / "pyproject.toml"
+    pyproject_toml.write_text(
+        textwrap.dedent(
+            """\
+            [tool.scikit-build]
+            minimum-version = "0.9"
+            """
+        ),
+        encoding="utf-8",
+    )
+    monkeypatch.setenv("SKBUILD_CMAKE_VERBOSE", "ON")
+    monkeypatch.setenv("SKBUILD_CMAKE_TARGETS", "a;b")
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {})
+    assert settings_reader.settings.build.verbose
+    assert settings_reader.settings.build.targets == ["a", "b"]
+
+
+def test_backcompat_cmake_build_both_specified(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+):
+    monkeypatch.setattr(
+        scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
+    )
+    pyproject_toml = tmp_path / "pyproject.toml"
+    pyproject_toml.write_text(
+        textwrap.dedent(
+            """\
+            [tool.scikit-build]
+            cmake.verbose = true
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    with pytest.raises(SystemExit):
+        SettingsReader.from_file(pyproject_toml, {"build.verbose": "1"})