From 679675cefb634b2715222cc09c77d5902dd0d176 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Mon, 25 Sep 2023 11:11:10 +0200 Subject: [PATCH 01/11] Add basic editable install navigation tests Signed-off-by: Cristian Le --- tests/conftest.py | 9 ++++ .../packages/navigate_editable/CMakeLists.txt | 15 ++++++ .../packages/navigate_editable/pyproject.toml | 10 ++++ .../python/shared_pkg/__init__.py | 4 ++ .../python/shared_pkg/c_module.pyi | 2 + .../python/shared_pkg/py_module.py | 9 ++++ .../src/shared_pkg/c_module.c | 49 +++++++++++++++++++ tests/test_editable.py | 23 +++++++++ 8 files changed, 121 insertions(+) create mode 100644 tests/packages/navigate_editable/CMakeLists.txt create mode 100644 tests/packages/navigate_editable/pyproject.toml create mode 100644 tests/packages/navigate_editable/python/shared_pkg/__init__.py create mode 100644 tests/packages/navigate_editable/python/shared_pkg/c_module.pyi create mode 100644 tests/packages/navigate_editable/python/shared_pkg/py_module.py create mode 100644 tests/packages/navigate_editable/src/shared_pkg/c_module.c create mode 100644 tests/test_editable.py diff --git a/tests/conftest.py b/tests/conftest.py index efc5fc0e9..6c65f1749 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -279,6 +279,15 @@ def package_simplest_c(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Packa return package +@pytest.fixture() +def navigate_editable(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> PackageInfo: + package = PackageInfo( + "navigate_editable", + ) + process_package(package, tmp_path, monkeypatch) + return package + + @pytest.fixture() def package_sdist_config( tmp_path: Path, monkeypatch: pytest.MonkeyPatch diff --git a/tests/packages/navigate_editable/CMakeLists.txt b/tests/packages/navigate_editable/CMakeLists.txt new file mode 100644 index 000000000..1be74befd --- /dev/null +++ b/tests/packages/navigate_editable/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.15...3.26) + +project( + ${SKBUILD_PROJECT_NAME} + LANGUAGES C + VERSION ${SKBUILD_PROJECT_VERSION}) + +find_package(Python COMPONENTS Interpreter Development.Module) + +python_add_library(c_module MODULE src/shared_pkg/c_module.c WITH_SOABI) + +install( + TARGETS c_module + DESTINATION shared_pkg/ + COMPONENT PythonModule) diff --git a/tests/packages/navigate_editable/pyproject.toml b/tests/packages/navigate_editable/pyproject.toml new file mode 100644 index 000000000..f8d9c9007 --- /dev/null +++ b/tests/packages/navigate_editable/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["scikit-build-core"] +build-backend = "scikit_build_core.build" + +[project] +name = "navigate_editable" +version = "0.0.1" + +[tool.scikit-build] +wheel.packages = ["python/shared_pkg"] diff --git a/tests/packages/navigate_editable/python/shared_pkg/__init__.py b/tests/packages/navigate_editable/python/shared_pkg/__init__.py new file mode 100644 index 000000000..ecbbeac9f --- /dev/null +++ b/tests/packages/navigate_editable/python/shared_pkg/__init__.py @@ -0,0 +1,4 @@ +from .c_module import call_py_method +from .py_module import call_c_method + +__all__ = ["call_py_method", "call_c_method"] diff --git a/tests/packages/navigate_editable/python/shared_pkg/c_module.pyi b/tests/packages/navigate_editable/python/shared_pkg/c_module.pyi new file mode 100644 index 000000000..4636e1015 --- /dev/null +++ b/tests/packages/navigate_editable/python/shared_pkg/c_module.pyi @@ -0,0 +1,2 @@ +def c_method() -> str: ... +def call_py_method() -> None: ... diff --git a/tests/packages/navigate_editable/python/shared_pkg/py_module.py b/tests/packages/navigate_editable/python/shared_pkg/py_module.py new file mode 100644 index 000000000..c4a71545f --- /dev/null +++ b/tests/packages/navigate_editable/python/shared_pkg/py_module.py @@ -0,0 +1,9 @@ +from .c_module import c_method + + +def call_c_method(): + print(c_method()) + + +def py_method(): + print("py_method") diff --git a/tests/packages/navigate_editable/src/shared_pkg/c_module.c b/tests/packages/navigate_editable/src/shared_pkg/c_module.c new file mode 100644 index 000000000..a5ceb95fb --- /dev/null +++ b/tests/packages/navigate_editable/src/shared_pkg/c_module.c @@ -0,0 +1,49 @@ +#define PY_SSIZE_T_CLEAN +#include +#include +#include + +const char* c_method() { return "c_method"; } + +static PyObject *c_method_wrapper(PyObject *self, PyObject *args) { + return PyUnicode_FromString(c_method()); +} + +static PyObject *py_method_wrapper(PyObject *self, PyObject *args) { + PyObject *py_module = PyImport_ImportModule("shared_pkg.py_module"); + if (py_module == NULL) { + PyErr_Print(); + fprintf(stderr, "Failed to load shared_pkg.py_module\n"); + exit(1); + } + PyObject *py_method = PyObject_GetAttrString(py_module,(char*)"py_method"); + if (py_method == NULL) { + PyErr_Print(); + fprintf(stderr, "Failed to load shared_pkg.py_module.py_method\n"); + exit(1); + } + + PyObject *res = PyObject_CallNoArgs(py_method); + if (res == NULL) { + PyErr_Print(); + fprintf(stderr, "Failed to execute shared_pkg.py_module.py_method\n"); + exit(1); + } + + Py_DECREF(py_module); + Py_DECREF(py_method); + Py_DECREF(res); + Py_RETURN_NONE; +} + +static PyMethodDef c_module_methods[] = { + {"c_method", c_method_wrapper, METH_NOARGS, "C native method"}, + {"call_py_method", py_method_wrapper, METH_NOARGS, "Call python native method"}, + {NULL, NULL, 0, NULL}}; + +static struct PyModuleDef c_module = {PyModuleDef_HEAD_INIT, "c_module", + NULL, -1, c_module_methods}; + +PyMODINIT_FUNC PyInit_c_module(void) { + return PyModule_Create(&c_module); +} diff --git a/tests/test_editable.py b/tests/test_editable.py new file mode 100644 index 000000000..95e76a07a --- /dev/null +++ b/tests/test_editable.py @@ -0,0 +1,23 @@ +import pytest + + +@pytest.mark.compile() +@pytest.mark.configure() +@pytest.mark.integration() +@pytest.mark.parametrize("isolate", [True, False]) +@pytest.mark.usefixtures("navigate_editable") +def test_navigate_editable(isolated, isolate): + isolate_args = ["--no-build-isolation"] if not isolate else [] + isolated.install("pip>=23") + if not isolate: + isolated.install("scikit-build-core[pyproject]") + + isolated.install( + "-v", "--config-settings=build-dir=build/{wheel_tag}", *isolate_args, "-e", "." + ) + + value = isolated.execute("import shared_pkg; shared_pkg.call_c_method()") + assert value == "c_method" + + value = isolated.execute("import shared_pkg; shared_pkg.call_py_method()") + assert value == "py_method" From 8a1f64510d3478f45e2cd22d8aa337ecfa3ede22 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Wed, 27 Sep 2023 19:04:12 +0200 Subject: [PATCH 02/11] Add importlib.resources test Signed-off-by: Cristian Le --- .../packages/navigate_editable/CMakeLists.txt | 6 ++++++ .../packages/navigate_editable/pyproject.toml | 3 +++ .../python/shared_pkg/__init__.py | 9 +++++++-- .../python/shared_pkg/data/py_data.txt | 1 + .../python/shared_pkg/py_module.py | 19 +++++++++++++++++++ .../src/shared_pkg/data/generated.txt.in | 1 + tests/test_editable.py | 6 ++++++ 7 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/packages/navigate_editable/python/shared_pkg/data/py_data.txt create mode 100644 tests/packages/navigate_editable/src/shared_pkg/data/generated.txt.in diff --git a/tests/packages/navigate_editable/CMakeLists.txt b/tests/packages/navigate_editable/CMakeLists.txt index 1be74befd..2c7f3e2e6 100644 --- a/tests/packages/navigate_editable/CMakeLists.txt +++ b/tests/packages/navigate_editable/CMakeLists.txt @@ -9,7 +9,13 @@ find_package(Python COMPONENTS Interpreter Development.Module) python_add_library(c_module MODULE src/shared_pkg/c_module.c WITH_SOABI) +set(CMakeVar "Some_value_C") +configure_file(src/shared_pkg/data/generated.txt.in + shared_pkg/data/c_generated.txt) + install( TARGETS c_module DESTINATION shared_pkg/ COMPONENT PythonModule) +install(FILES ${PROJECT_BINARY_DIR}/shared_pkg/data/c_generated.txt + DESTINATION shared_pkg/data/) diff --git a/tests/packages/navigate_editable/pyproject.toml b/tests/packages/navigate_editable/pyproject.toml index f8d9c9007..abaef4e82 100644 --- a/tests/packages/navigate_editable/pyproject.toml +++ b/tests/packages/navigate_editable/pyproject.toml @@ -5,6 +5,9 @@ build-backend = "scikit_build_core.build" [project] name = "navigate_editable" version = "0.0.1" +dependencies = [ + "importlib-resources; python_version<'3.9'" +] [tool.scikit-build] wheel.packages = ["python/shared_pkg"] diff --git a/tests/packages/navigate_editable/python/shared_pkg/__init__.py b/tests/packages/navigate_editable/python/shared_pkg/__init__.py index ecbbeac9f..63096923e 100644 --- a/tests/packages/navigate_editable/python/shared_pkg/__init__.py +++ b/tests/packages/navigate_editable/python/shared_pkg/__init__.py @@ -1,4 +1,9 @@ from .c_module import call_py_method -from .py_module import call_c_method +from .py_module import call_c_method, read_c_generated_txt, read_py_data_txt -__all__ = ["call_py_method", "call_c_method"] +__all__ = [ + "call_py_method", + "call_c_method", + "read_py_data_txt", + "read_c_generated_txt", +] diff --git a/tests/packages/navigate_editable/python/shared_pkg/data/py_data.txt b/tests/packages/navigate_editable/python/shared_pkg/data/py_data.txt new file mode 100644 index 000000000..21fb55e18 --- /dev/null +++ b/tests/packages/navigate_editable/python/shared_pkg/data/py_data.txt @@ -0,0 +1 @@ +Some_value_Py diff --git a/tests/packages/navigate_editable/python/shared_pkg/py_module.py b/tests/packages/navigate_editable/python/shared_pkg/py_module.py index c4a71545f..c0d9bef15 100644 --- a/tests/packages/navigate_editable/python/shared_pkg/py_module.py +++ b/tests/packages/navigate_editable/python/shared_pkg/py_module.py @@ -1,3 +1,10 @@ +import sys + +if sys.version_info < (3, 9): + from importlib_resources import files # noqa: TID251 +else: + from importlib.resources import files # noqa: TID251 + from .c_module import c_method @@ -7,3 +14,15 @@ def call_c_method(): def py_method(): print("py_method") + + +def read_py_data_txt(): + root = files("shared_pkg.data") + py_data = root / "py_data.txt" + print(py_data.read_text()) + + +def read_c_generated_txt(): + root = files("shared_pkg.data") + c_generated_txt = root / "c_generated.txt" + print(c_generated_txt.read_text()) diff --git a/tests/packages/navigate_editable/src/shared_pkg/data/generated.txt.in b/tests/packages/navigate_editable/src/shared_pkg/data/generated.txt.in new file mode 100644 index 000000000..40bda1771 --- /dev/null +++ b/tests/packages/navigate_editable/src/shared_pkg/data/generated.txt.in @@ -0,0 +1 @@ +@CMakeVar@ diff --git a/tests/test_editable.py b/tests/test_editable.py index 95e76a07a..a5231399d 100644 --- a/tests/test_editable.py +++ b/tests/test_editable.py @@ -21,3 +21,9 @@ def test_navigate_editable(isolated, isolate): value = isolated.execute("import shared_pkg; shared_pkg.call_py_method()") assert value == "py_method" + + value = isolated.execute("import shared_pkg; shared_pkg.read_py_data_txt()") + assert value == "Some_value_Py" + + value = isolated.execute("import shared_pkg; shared_pkg.read_c_generated_txt()") + assert value == "Some_value_C" From 37d03ccf1534c2f663942ebbb071f4d58a9632b6 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Thu, 28 Sep 2023 11:44:29 +0200 Subject: [PATCH 03/11] Implement `importlib.resources` support Signed-off-by: Cristian Le --- .../resources/_editable_redirect.py | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/scikit_build_core/resources/_editable_redirect.py b/src/scikit_build_core/resources/_editable_redirect.py index 886ee6b2c..ee08e9b51 100644 --- a/src/scikit_build_core/resources/_editable_redirect.py +++ b/src/scikit_build_core/resources/_editable_redirect.py @@ -36,6 +36,35 @@ def __init__( self.verbose = verbose self.build_options = build_options self.install_options = install_options + # Construct the __path__ of all resource files + # I.e. the paths of all package-like objects + submodule_search_locations: dict[str, set[str]] = {} + pkgs: list[str] = [] + # Loop over both python native source files and cmake installed ones + for tree in (known_source_files, known_wheel_files): + for module, file in tree.items(): + # Strip the last element of the module + parent = ".".join(module.split(".")[:-1]) + # Check if it is a package + if "__init__.py" in file: + parent = module + pkgs.append(parent) + # Skip if it's a root module (there are no search paths for these) + if not parent: + continue + # Initialize the tree element if needed + submodule_search_locations.setdefault(parent, set()) + # Add the parent path to the dictionary values + parent_path, _ = os.path.split(file) + if not parent_path: + # root modules are skipped so all files should be in a parent package + msg = f"Unexpected path to source file: {file} [{module}]" + raise ImportError(msg) + if not os.path.isabs(parent_path): + parent_path = os.path.join(str(DIR), parent_path) + submodule_search_locations[parent].add(parent_path) + self.submodule_search_locations = submodule_search_locations + self.pkgs = pkgs def find_spec( self, @@ -43,17 +72,32 @@ def find_spec( path: object = None, target: object = None, ) -> importlib.machinery.ModuleSpec | None: + # If current item is a know package use its search locations, otherwise if it's a module use the parent's + parent = ( + fullname if fullname in self.pkgs else ".".join(fullname.split(".")[:-1]) + ) + # If no known submodule_search_locations is found, it means it is a root module. Do not populate its kwargs + # in that case + kwargs = {} + if parent in self.submodule_search_locations: + kwargs["submodule_search_locations"] = list( + self.submodule_search_locations[parent] + ) if fullname in self.known_wheel_files: redir = self.known_wheel_files[fullname] if self.rebuild_flag: self.rebuild() + # Note: MyPy reports wrong type for `submodule_search_locations` return importlib.util.spec_from_file_location( - fullname, os.path.join(DIR, redir) + fullname, + os.path.join(DIR, redir), + **kwargs, # type: ignore[arg-type] ) if fullname in self.known_source_files: redir = self.known_source_files[fullname] - return importlib.util.spec_from_file_location(fullname, redir) - + return importlib.util.spec_from_file_location( + fullname, redir, **kwargs # type: ignore[arg-type] + ) return None def rebuild(self) -> None: From 142227e84c6a1a2c2f32d6a63bd235953c62b290 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Thu, 28 Sep 2023 18:41:33 +0200 Subject: [PATCH 04/11] Fix test_pep660 Signed-off-by: Cristian Le --- tests/conftest.py | 6 ++++++ tests/test_pyproject_pep660.py | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6c65f1749..ef52183f2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,6 +92,12 @@ def __init__(self, env_dir: Path, *, wheelhouse: Path | None = None) -> None: self.wheelhouse = wheelhouse self.executable = Path(result.creator.exe) self.env_dir = env_dir.resolve() + self.platlib = Path( + self.execute("import sysconfig; print(sysconfig.get_path('platlib'))") + ) + self.purelib = Path( + self.execute("import sysconfig; print(sysconfig.get_path('purelib'))") + ) @overload def run(self, *args: str, capture: Literal[True]) -> str: diff --git a/tests/test_pyproject_pep660.py b/tests/test_pyproject_pep660.py index 80123bff2..b8a1dfd10 100644 --- a/tests/test_pyproject_pep660.py +++ b/tests/test_pyproject_pep660.py @@ -58,7 +58,18 @@ def test_pep660_pip_isolated(isolated, isolate): assert value == "4.0" location = isolated.execute("import simplest; print(*simplest.__path__)") - assert location == str(Path.cwd() / "src/simplest") + # First path is from the python source + assert str(Path.cwd() / "src" / "simplest") in location + # Second path is from the CMake install + assert str(isolated.platlib / "simplest") in location location = isolated.execute("import simplest; print(simplest.__file__)") - assert location == str(Path.cwd() / "src/simplest/__init__.py") + # The package file is defined in the python source and __file__ must point to it + assert location == str(Path.cwd() / "src" / "simplest" / "__init__.py") + + location = isolated.execute( + "import simplest._module; print(simplest._module.__file__)" + ) + # The compiled module should point to the cmake install location + # The suffix path depends on compiler, only checking the installation location and base name + assert location.startswith(str(isolated.platlib / "simplest" / "_module.")) From 4c6765b8110a64f7d14753bd183783dcf978ce3d Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Thu, 28 Sep 2023 19:04:58 +0200 Subject: [PATCH 05/11] Fix support for testing python < 3.9 Signed-off-by: Cristian Le --- tests/packages/navigate_editable/src/shared_pkg/c_module.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/packages/navigate_editable/src/shared_pkg/c_module.c b/tests/packages/navigate_editable/src/shared_pkg/c_module.c index a5ceb95fb..3898e2d0f 100644 --- a/tests/packages/navigate_editable/src/shared_pkg/c_module.c +++ b/tests/packages/navigate_editable/src/shared_pkg/c_module.c @@ -23,7 +23,12 @@ static PyObject *py_method_wrapper(PyObject *self, PyObject *args) { exit(1); } +#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 8 PyObject *res = PyObject_CallNoArgs(py_method); +#else + PyObject *res = PyObject_CallObject(py_method, NULL); +#endif + if (res == NULL) { PyErr_Print(); fprintf(stderr, "Failed to execute shared_pkg.py_module.py_method\n"); From f4cddf0c3ea6c135118fef056eda20b452f2f4b2 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 30 Sep 2023 01:05:58 -0400 Subject: [PATCH 06/11] fix(types): Use TypedDict to avoid type ignores Signed-off-by: Henry Schreiner Remove leftover comment Co-authored-by: Henry Schreiner --- pyproject.toml | 2 +- .../resources/_editable_redirect.py | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c04af273f..79a858efc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -271,7 +271,7 @@ exclude = [] [tool.ruff.per-file-ignores] "tests/**" = ["T20"] "noxfile.py" = ["T20", "TID251"] -"src/scikit_build_core/resources/*.py" = ["PTH", "ARG002", "FBT"] +"src/scikit_build_core/resources/*.py" = ["PTH", "ARG002", "FBT", "TID251"] "src/scikit_build_core/_compat/**.py" = ["TID251"] "tests/conftest.py" = ["TID251"] "docs/conf.py" = ["TID251"] diff --git a/src/scikit_build_core/resources/_editable_redirect.py b/src/scikit_build_core/resources/_editable_redirect.py index ee08e9b51..9f0ddace5 100644 --- a/src/scikit_build_core/resources/_editable_redirect.py +++ b/src/scikit_build_core/resources/_editable_redirect.py @@ -1,12 +1,27 @@ from __future__ import annotations import importlib.abc -import importlib.machinery import importlib.util import os import subprocess import sys +TYPE_CHECKING = False +if TYPE_CHECKING: + import importlib.machinery + + if sys.version_info < (3, 8): + from typing_extensions import TypedDict + else: + from typing import TypedDict + + class KWDict_1(TypedDict, total=False): + submodule_search_locations: list[str] + +else: + KWDict_1 = dict + + DIR = os.path.abspath(os.path.dirname(__file__)) MARKER = "SKBUILD_EDITABLE_SKIP" VERBOSE = "SKBUILD_EDITABLE_VERBOSE" @@ -78,7 +93,7 @@ def find_spec( ) # If no known submodule_search_locations is found, it means it is a root module. Do not populate its kwargs # in that case - kwargs = {} + kwargs = KWDict_1() if parent in self.submodule_search_locations: kwargs["submodule_search_locations"] = list( self.submodule_search_locations[parent] @@ -87,17 +102,14 @@ def find_spec( redir = self.known_wheel_files[fullname] if self.rebuild_flag: self.rebuild() - # Note: MyPy reports wrong type for `submodule_search_locations` return importlib.util.spec_from_file_location( fullname, os.path.join(DIR, redir), - **kwargs, # type: ignore[arg-type] + **kwargs, ) if fullname in self.known_source_files: redir = self.known_source_files[fullname] - return importlib.util.spec_from_file_location( - fullname, redir, **kwargs # type: ignore[arg-type] - ) + return importlib.util.spec_from_file_location(fullname, redir, **kwargs) return None def rebuild(self) -> None: From 8ba0774ed7861ae98d4b293327a65cf82dcd1773 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 30 Sep 2023 10:43:22 -0400 Subject: [PATCH 07/11] chore: minor touchup Signed-off-by: Henry Schreiner --- pyproject.toml | 1 + .../packages/navigate_editable/python/shared_pkg/py_module.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 79a858efc..ebd2b2d2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -274,6 +274,7 @@ exclude = [] "src/scikit_build_core/resources/*.py" = ["PTH", "ARG002", "FBT", "TID251"] "src/scikit_build_core/_compat/**.py" = ["TID251"] "tests/conftest.py" = ["TID251"] +"tests/packages/**.py" = ["TID251"] "docs/conf.py" = ["TID251"] diff --git a/tests/packages/navigate_editable/python/shared_pkg/py_module.py b/tests/packages/navigate_editable/python/shared_pkg/py_module.py index c0d9bef15..8ec79b73b 100644 --- a/tests/packages/navigate_editable/python/shared_pkg/py_module.py +++ b/tests/packages/navigate_editable/python/shared_pkg/py_module.py @@ -1,9 +1,9 @@ import sys if sys.version_info < (3, 9): - from importlib_resources import files # noqa: TID251 + from importlib_resources import files else: - from importlib.resources import files # noqa: TID251 + from importlib.resources import files from .c_module import c_method From 6260886cd759eef6f2053fd2abe9b90250f93f21 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 30 Sep 2023 13:03:12 -0400 Subject: [PATCH 08/11] tests: use samefile Signed-off-by: Henry Schreiner --- tests/test_pyproject_pep660.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/test_pyproject_pep660.py b/tests/test_pyproject_pep660.py index b8a1dfd10..4585ce684 100644 --- a/tests/test_pyproject_pep660.py +++ b/tests/test_pyproject_pep660.py @@ -57,15 +57,22 @@ def test_pep660_pip_isolated(isolated, isolate): value = isolated.execute("import simplest; print(simplest.square(2))") assert value == "4.0" - location = isolated.execute("import simplest; print(*simplest.__path__)") + location_str = isolated.execute( + "import simplest; print(*simplest.__path__, sep=';')" + ) + locations = [Path(s).resolve() for s in location_str.split(";")] + # First path is from the python source - assert str(Path.cwd() / "src" / "simplest") in location + python_source = Path("src/simplest").resolve() + assert any(x.samefile(python_source) for x in locations) + # Second path is from the CMake install - assert str(isolated.platlib / "simplest") in location + cmake_install = isolated.platlib.joinpath("simplest").resolve() + assert any(x.samefile(cmake_install) for x in locations) location = isolated.execute("import simplest; print(simplest.__file__)") # The package file is defined in the python source and __file__ must point to it - assert location == str(Path.cwd() / "src" / "simplest" / "__init__.py") + assert Path("src/simplest/__init__.py").resolve().samefile(Path(location).resolve()) location = isolated.execute( "import simplest._module; print(simplest._module.__file__)" From bee2bf0fbf0f27f2cbab2241ff2089777d61ac39 Mon Sep 17 00:00:00 2001 From: Cristian Le Date: Mon, 2 Oct 2023 11:14:34 +0200 Subject: [PATCH 09/11] tests: use samefile + EXT_SUFFIX Signed-off-by: Cristian Le --- tests/test_pyproject_pep660.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/test_pyproject_pep660.py b/tests/test_pyproject_pep660.py index 4585ce684..c66ff3f75 100644 --- a/tests/test_pyproject_pep660.py +++ b/tests/test_pyproject_pep660.py @@ -1,4 +1,5 @@ import sys +import sysconfig import zipfile from pathlib import Path @@ -77,6 +78,20 @@ def test_pep660_pip_isolated(isolated, isolate): location = isolated.execute( "import simplest._module; print(simplest._module.__file__)" ) - # The compiled module should point to the cmake install location - # The suffix path depends on compiler, only checking the installation location and base name - assert location.startswith(str(isolated.platlib / "simplest" / "_module.")) + if sys.version_info < (3, 8, 7): + import distutils.sysconfig # pylint: disable=deprecated-module + + ext_suffix = distutils.sysconfig.get_config_var("EXT_SUFFIX") + else: + ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") + + module_file = cmake_install / f"_module{ext_suffix}" + # Windows FindPython may produce the wrong extension + if ( + sys.version_info < (3, 8, 7) + and sys.platform.startswith("win") + and not module_file.is_file() + ): + module_file = cmake_install / "_module.pyd" + + assert module_file.samefile(Path(location).resolve()) From a28a8e6b54b6357098da544144b3b8dd98fdcd90 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 2 Oct 2023 17:28:38 -0400 Subject: [PATCH 10/11] ci: check 3.9 on macOS Signed-off-by: Henry Schreiner --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4aee9f47a..e03da15c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,9 @@ jobs: - python-version: "3.9" runs-on: ubuntu-latest cmake-version: "3.20.x" + - python-version: "3.9" + runs-on: macos-latest + cmake-version: "3.18.x" - python-version: "3.10" runs-on: ubuntu-latest cmake-version: "3.22.x" From 2972c04728e588c47928caa6e434b79a6ba65bf2 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Wed, 4 Oct 2023 23:04:40 -0400 Subject: [PATCH 11/11] tests: parametrize on data package Signed-off-by: Henry Schreiner --- tests/test_editable.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/test_editable.py b/tests/test_editable.py index a5231399d..1b3805d2a 100644 --- a/tests/test_editable.py +++ b/tests/test_editable.py @@ -1,17 +1,38 @@ +import sys +from pathlib import Path + import pytest @pytest.mark.compile() @pytest.mark.configure() @pytest.mark.integration() -@pytest.mark.parametrize("isolate", [True, False]) +@pytest.mark.parametrize("isolate", [True, False], ids=["isolated", "notisolated"]) +@pytest.mark.parametrize( + "package", + [ + pytest.param( + True, + id="package", + marks=[pytest.mark.xfail(reason="Only data folders supported currently")], + ), + pytest.param(False, id="datafolder"), + ], +) @pytest.mark.usefixtures("navigate_editable") -def test_navigate_editable(isolated, isolate): +@pytest.mark.xfail( + sys.version_info[:2] == (3, 9), reason="Python 3.9 not supported yet" +) +def test_navigate_editable(isolated, isolate, package): isolate_args = ["--no-build-isolation"] if not isolate else [] isolated.install("pip>=23") if not isolate: isolated.install("scikit-build-core[pyproject]") + if package: + init_py = Path("python/shared_pkg/data/__init__.py") + init_py.touch() + isolated.install( "-v", "--config-settings=build-dir=build/{wheel_tag}", *isolate_args, "-e", "." )