diff --git a/docs/reference/configs.md b/docs/reference/configs.md index 8c6e8b857..0a7563d08 100644 --- a/docs/reference/configs.md +++ b/docs/reference/configs.md @@ -249,7 +249,7 @@ print(mk_skbuild_docs()) ```{eval-rst} .. confval:: editable.mode - :type: ``"redirect" | "inplace"`` + :type: ``"redirect" | "inplace" | "build-dir"`` :default: "redirect" Select the editable mode to use. Can be "redirect" (default) or "inplace". diff --git a/src/scikit_build_core/build/_editable.py b/src/scikit_build_core/build/_editable.py index f92d203f9..44f874717 100644 --- a/src/scikit_build_core/build/_editable.py +++ b/src/scikit_build_core/build/_editable.py @@ -14,13 +14,44 @@ if typing.TYPE_CHECKING: from collections.abc import Sequence -__all__ = ["editable_redirect", "libdir_to_installed", "mapping_to_modules"] +__all__ = [ + "editable_build_dir", + "editable_redirect", + "libdir_to_installed", + "mapping_to_modules", +] def __dir__() -> list[str]: return __all__ +def editable_build_dir( + *, + source_files: dict[str, str], +) -> str: + """ + Prepare the contents of the _editable_redirect.py file as build-dir mode. + """ + + # We can reuse the `_editable_redirect.py` file without the rebuild/install + # feature and providing only source files to map. + editable_py = resources / "_editable_redirect.py" + editable_txt: str = editable_py.read_text(encoding="utf-8") + + # Wheel_files are always empty here. + wheel_files: dict[str, str] = {} + + arguments = ( + source_files, # known_source_files + wheel_files, # known_wheel_files + None, # path + ) + arguments_str = ", ".join(repr(x) for x in arguments) + editable_txt += f"\n\ninstall({arguments_str})\n" + return editable_txt + + def editable_redirect( *, modules: dict[str, str], diff --git a/src/scikit_build_core/build/wheel.py b/src/scikit_build_core/build/wheel.py index 670419d33..b65e08856 100644 --- a/src/scikit_build_core/build/wheel.py +++ b/src/scikit_build_core/build/wheel.py @@ -23,7 +23,12 @@ from ..errors import FailedLiveProcessError from ..format import pyproject_format from ..settings.skbuild_read_settings import SettingsReader -from ._editable import editable_redirect, libdir_to_installed, mapping_to_modules +from ._editable import ( + editable_build_dir, + editable_redirect, + libdir_to_installed, + mapping_to_modules, +) from ._init import setup_logging from ._pathutil import ( packages_to_file_mapping, @@ -56,22 +61,36 @@ def _make_editable( settings: ScikitBuildSettings, wheel: WheelWriter, packages: Iterable[str], + mode: Literal["redirect", "inplace", "build-dir"], ) -> None: modules = mapping_to_modules(mapping, libdir) installed = libdir_to_installed(libdir) if settings.wheel.install_dir.startswith("/"): msg = "Editable installs cannot rebuild an absolute wheel.install-dir. Use an override to change if needed." raise AssertionError(msg) - editable_txt = editable_redirect( - modules=modules, - installed=installed, - reload_dir=reload_dir, - rebuild=settings.editable.rebuild, - verbose=settings.editable.verbose, - build_options=build_options, - install_options=install_options, - install_dir=settings.wheel.install_dir, - ) + if mode == "redirect": + editable_txt = editable_redirect( + modules=modules, + installed=installed, + reload_dir=reload_dir, + rebuild=settings.editable.rebuild, + verbose=settings.editable.verbose, + build_options=build_options, + install_options=install_options, + install_dir=settings.wheel.install_dir, + ) + elif mode == "build-dir": + if not settings.build_dir: + msg = "Editable mode build-dir must have the build-dir option set." + raise ValueError(msg) + source_files = modules + # TODO: get the source files from the build-dir + editable_txt = editable_build_dir( + source_files=source_files, + ) + else: + msg = f"Unexpected editable mode used: {mode}" + raise NotImplementedError(msg) wheel.writestr( f"_{name}_editable.py", @@ -500,7 +519,7 @@ def _build_wheel_impl_impl( str_pkgs = ( str(Path.cwd().joinpath(p).parent.resolve()) for p in packages.values() ) - if editable and settings.editable.mode == "redirect": + if editable and settings.editable.mode in ("redirect", "build-dir"): reload_dir = build_dir.resolve() if settings.build_dir else None _make_editable( @@ -513,6 +532,7 @@ def _build_wheel_impl_impl( wheel=wheel, name=normalized_name, packages=str_pkgs, + mode=settings.editable.mode, ) elif editable and settings.editable.mode == "inplace": if not packages: diff --git a/src/scikit_build_core/resources/scikit-build.schema.json b/src/scikit_build_core/resources/scikit-build.schema.json index 5065b4153..385985450 100644 --- a/src/scikit_build_core/resources/scikit-build.schema.json +++ b/src/scikit_build_core/resources/scikit-build.schema.json @@ -260,7 +260,8 @@ "mode": { "enum": [ "redirect", - "inplace" + "inplace", + "build-dir" ], "default": "redirect", "description": "Select the editable mode to use. Can be \"redirect\" (default) or \"inplace\"." diff --git a/src/scikit_build_core/settings/skbuild_model.py b/src/scikit_build_core/settings/skbuild_model.py index a83abd2f8..f128a818b 100644 --- a/src/scikit_build_core/settings/skbuild_model.py +++ b/src/scikit_build_core/settings/skbuild_model.py @@ -327,7 +327,7 @@ class BackportSettings: @dataclasses.dataclass class EditableSettings: - mode: Literal["redirect", "inplace"] = "redirect" + mode: Literal["redirect", "inplace", "build-dir"] = "redirect" """ Select the editable mode to use. Can be "redirect" (default) or "inplace". """