Repository: scikit-build/scikit-build-core
Pull request #1054 (2025-04-24 19:23:05)

fix: support overriding renamed options
Fix https://github.com/scikit-build/scikit-build-core/issues/912.

Now envvar and config options won't trigger the error, only statically defined ones will. And you can override a static option with the renamed new option. 

Also minor fix for a missing `env=env` passthrough for the API.


Patch:
diff --git a/src/scikit_build_core/settings/skbuild_read_settings.py b/src/scikit_build_core/settings/skbuild_read_settings.py
index a3bd624..ecfb998 100644
--- a/src/scikit_build_core/settings/skbuild_read_settings.py
+++ b/src/scikit_build_core/settings/skbuild_read_settings.py
@@ -92,12 +92,18 @@ def _handle_move(
     after: T,
     minimum_version: Version | None,
     introduced_in: Version,
+    *,
+    static: bool,
 ) -> 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:
+    if (
+        static
+        and after
+        and minimum_version is not None
+        and minimum_version < introduced_in
+    ):
         rich_error(
             f"Cannot set {after_name} if minimum-version is set to less than {introduced_in} (which is where it was introduced)"
         )
@@ -112,6 +118,8 @@ def _handle_move(
         )
 
     if before is not None and after:
+        if not static:
+            return after
         rich_error(f"Cannot set {before_name} and {after_name} at the same time")
 
     if before is None:
@@ -190,7 +198,7 @@ class SettingsReader:
             k: v for k, v in config_settings.items() if not k.startswith("skbuild.")
         }
         self.sources = SourceChain(
-            EnvSource("SKBUILD"),
+            EnvSource("SKBUILD", env=env),
             ConfSource("skbuild", settings=prefixed, verify=verify_conf),
             ConfSource(settings=remaining, verify=verify_conf),
             *toml_srcs,
@@ -198,6 +206,10 @@ class SettingsReader:
         )
         self.settings = self.sources.convert_target(ScikitBuildSettings)
 
+        static_settings = SourceChain(
+            *toml_srcs, prefixes=["tool", "scikit-build"]
+        ).convert_target(ScikitBuildSettings)
+
         if self.settings.minimum_version:
             current_version = Version(__version__)
             minimum_version = self.settings.minimum_version
@@ -285,6 +297,8 @@ class SettingsReader:
             self.settings.build.verbose,
             self.settings.minimum_version,
             Version("0.10"),
+            static=static_settings.cmake.verbose == self.settings.cmake.verbose
+            and static_settings.build.verbose == self.settings.build.verbose,
         )
         self.settings.build.targets = _handle_move(
             "cmake.targets",
@@ -293,6 +307,8 @@ class SettingsReader:
             self.settings.build.targets,
             self.settings.minimum_version,
             Version("0.10"),
+            static=static_settings.cmake.targets == self.settings.cmake.targets
+            and static_settings.build.targets == self.settings.build.targets,
         )
 
     def unrecognized_options(self) -> Generator[str, None, None]:


Test patch:
diff --git a/tests/test_skbuild_settings.py b/tests/test_skbuild_settings.py
index 88ed4a6..5da9199 100644
--- a/tests/test_skbuild_settings.py
+++ b/tests/test_skbuild_settings.py
@@ -624,27 +624,6 @@ def test_backcompat_cmake_build_env(tmp_path: Path, monkeypatch: pytest.MonkeyPa
     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"})
-
-
 def test_auto_minimum_version(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
     monkeypatch.setattr(
         scikit_build_core.settings.skbuild_read_settings, "__version__", "0.10.0"
@@ -813,3 +792,135 @@ def test_skbuild_settings_cmake_define_list():
         "NESTED_LIST": r"Apple;Lemon\;Lime;Banana",
         "ONE_LEVEL_LIST": "Foo;Bar;ExceptionallyLargeListEntryThatWouldOverflowTheLine;Baz",
     }
+
+
+def test_skbuild_override_renamed(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+    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.7"
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {"build.verbose": "1"})
+    assert settings_reader.settings.build.verbose
+
+    settings_reader = SettingsReader.from_file(
+        pyproject_toml, env={"SKBUILD_BUILD_VERBOSE": "TRUE"}
+    )
+    assert settings_reader.settings.build.verbose
+
+
+def test_skbuild_override_renamed_fail(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+    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.7"
+            build.verbose = true
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    with pytest.raises(SystemExit):
+        SettingsReader.from_file(pyproject_toml)
+
+
+def test_skbuild_override_static(
+    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
+) -> None:
+    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.7"
+            build.verbose = true
+            """
+        ),
+        encoding="utf-8",
+    )
+    with pytest.raises(SystemExit):
+        SettingsReader.from_file(pyproject_toml)
+
+
+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",
+    )
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {"build.verbose": "1"})
+    assert settings_reader.settings.build.verbose
+
+
+def test_backcompat_cmake_build_both_specified_static(
+    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]
+            build.verbose = true
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {"cmake.verbose": "1"})
+    assert settings_reader.settings.build.verbose
+
+
+def test_backcompat_cmake_build_targets_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.targets = ["a", "b"]
+            """
+        ),
+        encoding="utf-8",
+    )
+
+    settings_reader = SettingsReader.from_file(pyproject_toml, {"build.targets": "c;d"})
+    assert settings_reader.settings.build.targets == ["c", "d"]