From 7321e3c0fded769ec9280b86f596ceceace44ece Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 13 Jul 2024 10:13:28 -0700 Subject: [PATCH 1/2] Demonstrate where a potential fix could be and why it doesn't seem to work --- .../resources/_editable_redirect.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/scikit_build_core/resources/_editable_redirect.py b/src/scikit_build_core/resources/_editable_redirect.py index 677f37ac..265ec838 100644 --- a/src/scikit_build_core/resources/_editable_redirect.py +++ b/src/scikit_build_core/resources/_editable_redirect.py @@ -2,6 +2,8 @@ import importlib.abc import importlib.util +import importlib.machinery +import importlib.readers # Might be Python version specific? import os import subprocess import sys @@ -76,6 +78,26 @@ def release(self) -> None: fcntl.flock(self.lock_file_fd, fcntl.LOCK_UN) os.close(self.lock_file_fd) +# Note: This solution relies on importlib's call stack in Python 3.11. Python 3.9 looks +# different, so might require a different solution, but I haven't gone deeper into that +# yet since I don't have a solution for the 3.11 case yet anyway. +class ScikitBuildRedirectingReader(importlib.readers.FileReader): + def files(self): + # ATTENTION: This is where the problem is. The expectation is that this returns + # a Traversable object. We could hack together an object that satisfies that + # API, but methods like `joinpath` don't have sensible implementations if + # `files` could return multiple paths instead of a single one. We could do some + # hackery to figure out which paths exist on the backend by hiding some internal + # representation that knows both possible roots and checks for existence when + # necessary, but that seriously violates the principle of least surprise for the + # user so I'd be quite skeptical. + return self.path + + +class ScikitBuildRedirectingLoader(importlib.machinery.SourceFileLoader): + def get_resource_reader(self, module): + return ScikitBuildRedirectingReader(self) + class ScikitBuildRedirectingFinder(importlib.abc.MetaPathFinder): def __init__( @@ -153,6 +175,7 @@ def find_spec( submodule_search_locations=submodule_search_locations if redir.endswith(("__init__.py", "__init__.pyc")) else None, + loader=ScikitBuildRedirectingLoader(fullname, os.path.join(self.dir, redir)), ) if fullname in self.known_source_files: redir = self.known_source_files[fullname] @@ -162,6 +185,7 @@ def find_spec( submodule_search_locations=submodule_search_locations if redir.endswith(("__init__.py", "__init__.pyc")) else None, + loader=ScikitBuildRedirectingLoader(fullname, redir), ) return None From 65b66fea7742a87b5c9624f2b0d5b0a23770c431 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 1 Apr 2025 13:58:32 -0700 Subject: [PATCH 2/2] Fix or ignore all style errors --- .../resources/_editable_redirect.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/scikit_build_core/resources/_editable_redirect.py b/src/scikit_build_core/resources/_editable_redirect.py index 265ec838..a3147d3f 100644 --- a/src/scikit_build_core/resources/_editable_redirect.py +++ b/src/scikit_build_core/resources/_editable_redirect.py @@ -1,9 +1,11 @@ from __future__ import annotations import importlib.abc -import importlib.util import importlib.machinery -import importlib.readers # Might be Python version specific? + +# TODO: importlib.readers is Python version specific +import importlib.readers # type: ignore[import-not-found] +import importlib.util import os import subprocess import sys @@ -13,6 +15,7 @@ TYPE_CHECKING = False if TYPE_CHECKING: from importlib.machinery import ModuleSpec + from pathlib import Path DIR = os.path.abspath(os.path.dirname(__file__)) @@ -78,11 +81,12 @@ def release(self) -> None: fcntl.flock(self.lock_file_fd, fcntl.LOCK_UN) os.close(self.lock_file_fd) + # Note: This solution relies on importlib's call stack in Python 3.11. Python 3.9 looks # different, so might require a different solution, but I haven't gone deeper into that # yet since I don't have a solution for the 3.11 case yet anyway. -class ScikitBuildRedirectingReader(importlib.readers.FileReader): - def files(self): +class ScikitBuildRedirectingReader(importlib.readers.FileReader): # type: ignore[misc] + def files(self) -> Path: # ATTENTION: This is where the problem is. The expectation is that this returns # a Traversable object. We could hack together an object that satisfies that # API, but methods like `joinpath` don't have sensible implementations if @@ -91,11 +95,11 @@ def files(self): # representation that knows both possible roots and checks for existence when # necessary, but that seriously violates the principle of least surprise for the # user so I'd be quite skeptical. - return self.path + return self.path # type: ignore[no-any-return] class ScikitBuildRedirectingLoader(importlib.machinery.SourceFileLoader): - def get_resource_reader(self, module): + def get_resource_reader(self, module: str) -> ScikitBuildRedirectingReader: # type: ignore[override] return ScikitBuildRedirectingReader(self) @@ -175,7 +179,9 @@ def find_spec( submodule_search_locations=submodule_search_locations if redir.endswith(("__init__.py", "__init__.pyc")) else None, - loader=ScikitBuildRedirectingLoader(fullname, os.path.join(self.dir, redir)), + loader=ScikitBuildRedirectingLoader( + fullname, os.path.join(self.dir, redir) + ), ) if fullname in self.known_source_files: redir = self.known_source_files[fullname]