Skip to content

Commit 55908d9

Browse files
committed
Add a metadata to not allow hardcoded options
Signed-off-by: Cristian Le <[email protected]>
1 parent 0d27a42 commit 55908d9

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

src/scikit_build_core/settings/skbuild_model.py

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ def __dir__() -> List[str]:
3333
class SettingsFieldMetadata(TypedDict, total=False):
3434
display_default: Optional[str]
3535
deprecated: bool
36+
disallow_hard_code: bool
37+
"""Do not allow the field to be hard-coded in the pyproject table."""
3638

3739

3840
class CMakeSettingsDefine(str):

src/scikit_build_core/settings/skbuild_read_settings.py

+54
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import os
2525
from collections.abc import Generator, Mapping
2626

27+
from .skbuild_overrides import OverrideRecord
28+
2729

2830
__all__ = ["SettingsReader"]
2931

@@ -133,6 +135,57 @@ def _handle_move(
133135
return before
134136

135137

138+
def _validate_overrides(
139+
settings: ScikitBuildSettings,
140+
overrides: dict[str, OverrideRecord],
141+
) -> None:
142+
"""Validate all fields with any override information."""
143+
144+
def validate_field(
145+
field: dataclasses.Field[Any],
146+
value: Any,
147+
prefix: str = "",
148+
record: OverrideRecord | None = None,
149+
) -> None:
150+
"""Do the actual validation."""
151+
# Check if we had a hard-coded value in the record
152+
conf_key = field.name.replace("_", "-")
153+
if field.metadata.get("disallow_hard_code", False):
154+
original_value = record.original_value if record else value
155+
if original_value is not None:
156+
msg = f"{prefix}{conf_key} is not allowed to be hard-coded in the pyproject.toml file"
157+
if settings.strict_config:
158+
sys.stdout.flush()
159+
rich_print(f"{{bold.red}}ERROR:{{normal}} {msg}")
160+
raise SystemExit(7)
161+
logger.warning(msg)
162+
163+
def validate_field_recursive(
164+
obj: Any,
165+
record: OverrideRecord | None = None,
166+
prefix: str = "",
167+
) -> None:
168+
"""Navigate through all the keys and validate each field."""
169+
for field in dataclasses.fields(obj):
170+
conf_key = field.name.replace("_", "-")
171+
closest_record = overrides.get(f"{prefix}{conf_key}", record)
172+
value = getattr(obj, field.name)
173+
# Do the validation of the current field
174+
validate_field(
175+
field=field,
176+
value=value,
177+
prefix=prefix,
178+
record=closest_record,
179+
)
180+
if dataclasses.is_dataclass(value):
181+
validate_field_recursive(
182+
obj=value, record=closest_record, prefix=f"{prefix}{conf_key}."
183+
)
184+
185+
# Navigate all fields starting from the top-level
186+
validate_field_recursive(obj=settings)
187+
188+
136189
class SettingsReader:
137190
def __init__(
138191
self,
@@ -352,6 +405,7 @@ def validate_may_exit(self) -> None:
352405
self.print_suggestions()
353406
raise SystemExit(7)
354407
logger.warning("Unrecognized options: {}", ", ".join(unrecognized))
408+
_validate_overrides(self.settings, self.overriden_items)
355409

356410
for key, value in self.settings.metadata.items():
357411
if "provider" not in value:

0 commit comments

Comments
 (0)