diff --git a/src/scikit_build_core/settings/documentation.py b/src/scikit_build_core/settings/documentation.py index cd6fc1cb8..06dadb360 100644 --- a/src/scikit_build_core/settings/documentation.py +++ b/src/scikit_build_core/settings/documentation.py @@ -4,17 +4,19 @@ import dataclasses import inspect import textwrap +import typing from pathlib import Path -from typing import TYPE_CHECKING from packaging.specifiers import SpecifierSet from packaging.version import Version +from .. import __version__ from .._compat.typing import get_args, get_origin -if TYPE_CHECKING: +if typing.TYPE_CHECKING: from collections.abc import Generator + __all__ = ["pull_docs"] @@ -22,6 +24,9 @@ def __dir__() -> list[str]: return __all__ +version_display = ".".join(__version__.split(".")[:2]) + + def _get_value(value: ast.expr) -> str: assert isinstance(value, ast.Constant) assert isinstance(value.value, str) @@ -45,17 +50,22 @@ def pull_docs(dc: type[object]) -> dict[str, str]: } -@dataclasses.dataclass +@dataclasses.dataclass(frozen=True) class DCDoc: name: str default: str docs: str + deprecated: bool = False def __str__(self) -> str: docs = "\n".join(f"# {s}" for s in textwrap.wrap(self.docs, width=78)) return f"{docs}\n{self.name} = {self.default}\n" +def sanitize_default_field(text: str) -> str: + return text.replace("'", '"').replace("True", "true").replace("False", "false") + + def mk_docs(dc: type[object], prefix: str = "") -> Generator[DCDoc, None, None]: """ Makes documentation for a dataclass. @@ -75,7 +85,12 @@ def mk_docs(dc: type[object], prefix: str = "") -> Generator[DCDoc, None, None]: yield from mk_docs(field_type, prefix=f"{prefix}{field.name}[].") continue - if field.default is not dataclasses.MISSING and field.default is not None: + if default_before_format := field.metadata.get("display_default", None): + assert isinstance(default_before_format, str) + default = default_before_format.format( + version=version_display, + ) + elif field.default is not dataclasses.MISSING and field.default is not None: default = repr( str(field.default) if isinstance(field.default, (Path, Version, SpecifierSet)) @@ -87,7 +102,8 @@ def mk_docs(dc: type[object], prefix: str = "") -> Generator[DCDoc, None, None]: default = '""' yield DCDoc( - f"{prefix}{field.name}".replace("_", "-"), - default.replace("'", '"').replace("True", "true").replace("False", "false"), - docs[field.name], + name=f"{prefix}{field.name}".replace("_", "-"), + default=sanitize_default_field(default), + docs=docs[field.name], + deprecated=field.metadata.get("deprecated", False), ) diff --git a/src/scikit_build_core/settings/skbuild_docs.py b/src/scikit_build_core/settings/skbuild_docs.py index 65a03c34d..01723d3bb 100644 --- a/src/scikit_build_core/settings/skbuild_docs.py +++ b/src/scikit_build_core/settings/skbuild_docs.py @@ -1,6 +1,5 @@ from __future__ import annotations -from .. import __version__ from .documentation import mk_docs from .skbuild_model import ScikitBuildSettings @@ -11,24 +10,13 @@ def __dir__() -> list[str]: return __all__ -version = ".".join(__version__.split(".")[:2]) - -INV = {"cmake.minimum-version", "ninja.minimum-version"} - - def mk_skbuild_docs() -> str: """ Makes documentation for the skbuild model. """ - items = [x for x in mk_docs(ScikitBuildSettings) if x.name not in INV] - for item in items: - if item.name == "minimum-version": - item.default = f'"{version}" # current version' - if item.name == "install.strip": - item.default = "true" - if item.name == "wheel.packages": - item.default = '["src/", "python/", ""]' - return "\n".join(str(item) for item in items) + return "\n".join( + str(item) for item in mk_docs(ScikitBuildSettings) if not item.deprecated + ) if __name__ == "__main__": diff --git a/src/scikit_build_core/settings/skbuild_model.py b/src/scikit_build_core/settings/skbuild_model.py index adc92aaea..d25a4a843 100644 --- a/src/scikit_build_core/settings/skbuild_model.py +++ b/src/scikit_build_core/settings/skbuild_model.py @@ -1,6 +1,6 @@ import dataclasses from pathlib import Path -from typing import Any, Dict, List, Literal, Optional, Union +from typing import Any, Dict, List, Literal, Optional, TypedDict, Union from packaging.specifiers import SpecifierSet from packaging.version import Version @@ -21,6 +21,7 @@ "SDistSettings", "ScikitBuildSettings", "SearchSettings", + "SettingsFieldMetadata", "WheelSettings", ] @@ -29,6 +30,11 @@ def __dir__() -> List[str]: return __all__ +class SettingsFieldMetadata(TypedDict, total=False): + display_default: Optional[str] + deprecated: bool + + class CMakeSettingsDefine(str): """ A str subtype for automatically normalizing bool and list values @@ -53,7 +59,9 @@ def escape_semicolons(item: str) -> str: @dataclasses.dataclass class CMakeSettings: - minimum_version: Optional[Version] = None + minimum_version: Optional[Version] = dataclasses.field( + default=None, metadata=SettingsFieldMetadata(deprecated=True) + ) """ DEPRECATED in 0.8; use version instead. """ @@ -114,7 +122,9 @@ class SearchSettings: @dataclasses.dataclass class NinjaSettings: - minimum_version: Optional[Version] = None + minimum_version: Optional[Version] = dataclasses.field( + default=None, metadata=SettingsFieldMetadata(deprecated=True) + ) """ DEPRECATED in 0.8; use version instead. """ @@ -174,7 +184,12 @@ class SDistSettings: @dataclasses.dataclass class WheelSettings: - packages: Optional[Union[List[str], Dict[str, str]]] = None + packages: Optional[Union[List[str], Dict[str, str]]] = dataclasses.field( + default=None, + metadata=SettingsFieldMetadata( + display_default='["src/", "python/", ""]' + ), + ) """ A list of packages to auto-copy into the wheel. If this is not set, it will default to the first of ``src/``, ``python/``, or @@ -300,7 +315,9 @@ class InstallSettings: The components to install. If empty, all default components are installed. """ - strip: Optional[bool] = None + strip: Optional[bool] = dataclasses.field( + default=None, metadata=SettingsFieldMetadata(display_default="true") + ) """ Whether to strip the binaries. True for release builds on scikit-build-core 0.5+ (0.5-0.10.5 also incorrectly set this for debug builds). @@ -382,7 +399,12 @@ class ScikitBuildSettings: Enable early previews of features not finalized yet. """ - minimum_version: Optional[Version] = None + minimum_version: Optional[Version] = dataclasses.field( + default=None, + metadata=SettingsFieldMetadata( + display_default='"{version}" # current version' + ), + ) """ If set, this will provide a method for backward compatibility. """