Skip to content

Commit 5d10399

Browse files
committed
Save a record of the override actions
Used for further validations Signed-off-by: Cristian Le <git@lecris.dev>
1 parent bdf5a4a commit 5d10399

File tree

2 files changed

+101
-5
lines changed

2 files changed

+101
-5
lines changed

src/scikit_build_core/settings/skbuild_overrides.py

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from __future__ import annotations
22

3+
import dataclasses
34
import os
45
import platform
56
import re
67
import sys
78
from pathlib import Path
8-
from typing import TYPE_CHECKING, Any, Literal
9+
from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar
910

1011
import packaging.tags
1112
from packaging.specifiers import SpecifierSet
@@ -18,7 +19,7 @@
1819
from ..errors import CMakeNotFoundError
1920
from ..resources import resources
2021

21-
__all__ = ["process_overides", "regex_match"]
22+
__all__ = ["OverrideRecord", "process_overides", "regex_match"]
2223

2324

2425
def __dir__() -> list[str]:
@@ -29,6 +30,33 @@ def __dir__() -> list[str]:
2930
from collections.abc import Mapping
3031

3132

33+
T = TypeVar("T")
34+
35+
36+
@dataclasses.dataclass
37+
class OverrideRecord(Generic[T]):
38+
"""
39+
Record of the override action.
40+
41+
Saves the original and final values, and the override reasons.
42+
"""
43+
44+
key: str
45+
"""Settings key that is overridden."""
46+
original_value: T | None
47+
"""
48+
Original value in the pyproject table.
49+
50+
If the pyproject table did not have the key, this is a ``None``.
51+
"""
52+
value: T
53+
"""Final value."""
54+
passed_all: dict[str, str] | None
55+
"""All if statements that passed (except the effective ``match_any``)."""
56+
passed_any: dict[str, str] | None
57+
"""All if.any statements that passed."""
58+
59+
3260
def strtobool(value: str) -> bool:
3361
"""
3462
Converts a environment variable string into a boolean value.
@@ -257,20 +285,72 @@ def inherit_join(
257285
raise TypeError(msg)
258286

259287

288+
def record_override(
289+
*keys: str,
290+
value: Any,
291+
tool_skb: dict[str, Any],
292+
overriden_items: dict[str, OverrideRecord[Any]],
293+
passed_all: dict[str, str] | None,
294+
passed_any: dict[str, str] | None,
295+
) -> None:
296+
full_key = ".".join(keys)
297+
# Get the original_value to construct the record
298+
if full_key in overriden_items:
299+
# We found the original value from a previous override record
300+
original_value = overriden_items[full_key].original_value
301+
else:
302+
# Otherwise navigate the original pyproject table until we resolved all keys
303+
_dict_or_value = tool_skb
304+
keys_list = [*keys]
305+
while keys_list:
306+
k = keys_list.pop(0)
307+
if k not in _dict_or_value:
308+
# We hit a dead end so we imply the original_value was not set (`None`)
309+
original_value = None
310+
break
311+
_dict_or_value = _dict_or_value[k]
312+
if isinstance(_dict_or_value, dict):
313+
# If the value is a dict it is either the final value or we continue
314+
# to navigate it
315+
continue
316+
# Otherwise it should be the final value
317+
original_value = _dict_or_value
318+
if keys_list:
319+
msg = f"Could not navigate to the key {full_key} because {k} is a {type(_dict_or_value)}"
320+
raise TypeError(msg)
321+
break
322+
else:
323+
# We exhausted all keys so the current value should be the table key we are
324+
# interested in
325+
original_value = _dict_or_value
326+
# Now save the override record
327+
overriden_items[full_key] = OverrideRecord(
328+
key=keys[-1],
329+
original_value=original_value,
330+
value=value,
331+
passed_any=passed_any,
332+
passed_all=passed_all,
333+
)
334+
335+
260336
def process_overides(
261337
tool_skb: dict[str, Any],
262338
*,
263339
state: Literal["sdist", "wheel", "editable", "metadata_wheel", "metadata_editable"],
264340
retry: bool,
265341
env: Mapping[str, str] | None = None,
266-
) -> set[str]:
342+
) -> tuple[set[str], dict[str, OverrideRecord[Any]]]:
267343
"""
268344
Process overrides into the main dictionary if they match. Modifies the input
269345
dictionary. Must be run from the package directory.
346+
347+
:return: A tuple of the set of matching overrides and a dict of changed keys and
348+
override record
270349
"""
271350
has_dist_info = Path("PKG-INFO").is_file()
272351

273352
global_matched: set[str] = set()
353+
overriden_items: dict[str, OverrideRecord[Any]] = {}
274354
for override in tool_skb.pop("overrides", []):
275355
passed_any: dict[str, str] | None = None
276356
passed_all: dict[str, str] | None = None
@@ -354,17 +434,33 @@ def process_overides(
354434
inherit1 = inherit_override.get(key, {})
355435
if isinstance(value, dict):
356436
for key2, value2 in value.items():
437+
record_override(
438+
*[key, key2],
439+
value=value,
440+
tool_skb=tool_skb,
441+
overriden_items=overriden_items,
442+
passed_all=passed_all,
443+
passed_any=passed_any,
444+
)
357445
inherit2 = inherit1.get(key2, "none")
358446
inner = tool_skb.get(key, {})
359447
inner[key2] = inherit_join(
360448
value2, inner.get(key2, None), inherit2
361449
)
362450
tool_skb[key] = inner
363451
else:
452+
record_override(
453+
key,
454+
value=value,
455+
tool_skb=tool_skb,
456+
overriden_items=overriden_items,
457+
passed_all=passed_all,
458+
passed_any=passed_any,
459+
)
364460
inherit_override_tmp = inherit_override or "none"
365461
if isinstance(inherit_override_tmp, dict):
366462
assert not inherit_override_tmp
367463
tool_skb[key] = inherit_join(
368464
value, tool_skb.get(key), inherit_override_tmp
369465
)
370-
return global_matched
466+
return global_matched, overriden_items

src/scikit_build_core/settings/skbuild_read_settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def __init__(
151151

152152
# Handle overrides
153153
pyproject = copy.deepcopy(pyproject)
154-
self.overrides = process_overides(
154+
self.overrides, self.overriden_items = process_overides(
155155
pyproject.get("tool", {}).get("scikit-build", {}),
156156
state=state,
157157
env=env,

0 commit comments

Comments
 (0)