Skip to content

Commit 5770c6a

Browse files
committed
Unify search path handling
- Validate the path types of the entry-points - Update the entry-points values with the settings value - Flatten the entry-points to a list or add them as a dict - Print more debug messages - Fix the settings type to string Signed-off-by: Cristian Le <cristian.le@mpsd.mpg.de>
1 parent 0cf744c commit 5770c6a

File tree

4 files changed

+92
-45
lines changed

4 files changed

+92
-45
lines changed

src/scikit_build_core/_compat/importlib/resources.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,22 @@
77
else:
88
from importlib.resources import files
99

10-
__all__ = ["files"]
10+
if sys.version_info < (3, 10):
11+
# Readers were introduced in 3.10
12+
from importlib_resources import readers
13+
elif sys.version_info < (3, 11):
14+
# In 3.10 readers were implemented in importlib.readers
15+
from importlib import readers
16+
else:
17+
# From 3.11 it is accessed as importlib.resources.readers
18+
from importlib.resources import readers
19+
20+
if sys.version_info < (3, 11):
21+
from importlib_resources import abc
22+
else:
23+
from importlib.resources import abc
24+
25+
__all__ = ["files", "readers", "abc"]
1126

1227

1328
def __dir__() -> list[str]:

src/scikit_build_core/builder/builder.py

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,65 @@ def _filter_env_cmake_args(env_cmake_args: list[str]) -> Generator[str, None, No
8484
yield arg
8585

8686

87+
def _sanitize_path(path: resources.abc.Traversable) -> list[Path] | None:
88+
if isinstance(path, resources.readers.MultiplexedPath):
89+
return path._paths
90+
if isinstance(path, Path):
91+
return [path]
92+
logger.warning("Unknown path type: [{}] {}", type(path), path)
93+
return None
94+
95+
96+
def _handle_search_paths(
97+
entry_point: str,
98+
settings_val: list[str] | dict[str, str] | None,
99+
output: list[Path] | dict[str, list[Path]],
100+
) -> None:
101+
# Sanity checks
102+
if isinstance(output, dict):
103+
assert isinstance(settings_val, dict)
104+
105+
# Get the search paths from the entry points
106+
search_paths_dict = {}
107+
eps = metadata.entry_points(group=entry_point)
108+
if eps:
109+
logger.debug(
110+
"Loading search paths {} from entry-points: {}", entry_point, len(eps)
111+
)
112+
for ep in eps:
113+
ep_value = _sanitize_path(resources.files(ep.load()))
114+
logger.debug("{}: {} -> {}", ep.name, ep.value, ep_value)
115+
if ep_value:
116+
search_paths_dict[ep.name] = ep_value
117+
118+
# Update the search paths from the settings options
119+
if isinstance(settings_val, dict) and settings_val:
120+
logger.debug(
121+
"Overriding search paths {} from config: {}", entry_point, settings_val
122+
)
123+
for key, val in settings_val.items():
124+
if val:
125+
# TODO: Allow settings_val to be dict[str, list[str]]?
126+
search_paths_dict[key] = [Path(val)]
127+
else:
128+
search_paths_dict.pop(key)
129+
130+
# Write to the output
131+
if isinstance(output, list):
132+
search_paths_list = [
133+
path for ep_values in search_paths_dict.values() for path in ep_values
134+
]
135+
# If the settings options was a list the values are appended as-is
136+
if isinstance(settings_val, list) and settings_val:
137+
logger.debug(
138+
"Appending search paths {} with config: {}", entry_point, settings_val
139+
)
140+
search_paths_list += map(Path, settings_val)
141+
output.extend(search_paths_list)
142+
return
143+
output.update(search_paths_dict)
144+
145+
87146
@dataclasses.dataclass
88147
class Builder:
89148
settings: ScikitBuildSettings
@@ -123,47 +182,20 @@ def configure(
123182
}
124183

125184
# Add any extra CMake modules
126-
module_dirs_dict = {
127-
ep.name: resources.files(ep.load())
128-
for ep in metadata.entry_points(group="cmake.module")
129-
}
130-
if isinstance(self.settings.search.modules, dict):
131-
# Allow to override any entry-point definition
132-
module_dirs_dict.update(self.settings.search.modules)
133-
module_dirs = list(module_dirs_dict.values())
134-
if isinstance(self.settings.search.modules, list):
135-
# If it was a list, append to the entry-point definitions
136-
module_dirs += self.settings.search.modules
137-
# Remove any empty paths
138-
module_dirs = [path for path in module_dirs if path]
139-
self.config.module_dirs.extend(module_dirs)
185+
_handle_search_paths(
186+
"cmake.module", self.settings.search.modules, self.config.module_dirs
187+
)
140188

141189
# Add any extra CMake prefixes
142-
prefix_dirs_dict = {
143-
ep.name: resources.files(ep.load())
144-
for ep in metadata.entry_points(group="cmake.prefix")
145-
}
146-
if isinstance(self.settings.search.prefixes, dict):
147-
# Allow to override any entry-point definition
148-
prefix_dirs_dict.update(self.settings.search.prefixes)
149-
prefix_dirs = list(prefix_dirs_dict.values())
150-
if isinstance(self.settings.search.prefixes, list):
151-
# If it was a list, append to the entry-point definitions
152-
prefix_dirs += self.settings.search.prefixes
153-
# Remove any empty paths
154-
prefix_dirs = [path for path in prefix_dirs if path]
155-
self.config.prefix_dirs.extend(prefix_dirs)
190+
_handle_search_paths(
191+
"cmake.prefix", self.settings.search.prefixes, self.config.prefix_dirs
192+
)
156193

157194
# Add all CMake roots
158-
prefix_roots = {
159-
ep.name: resources.files(ep.load())
160-
for ep in metadata.entry_points(group="cmake.root")
161-
}
162195
# TODO: Check for unique uppercase names
163-
prefix_roots.update(self.settings.search.roots)
164-
# Remove any empty paths
165-
prefix_roots = {pkg: path for pkg, path in prefix_roots.items() if path}
166-
self.config.prefix_roots.update(prefix_roots)
196+
_handle_search_paths(
197+
"cmake.root", self.settings.search.roots, self.config.prefix_roots
198+
)
167199

168200
# Add site-packages to the prefix path for CMake
169201
site_packages = Path(sysconfig.get_path("purelib"))

src/scikit_build_core/cmake.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class CMaker:
7979
build_type: str
8080
module_dirs: list[Path] = dataclasses.field(default_factory=list)
8181
prefix_dirs: list[Path] = dataclasses.field(default_factory=list)
82-
prefix_roots: dict[str, Path] = dataclasses.field(default_factory=dict)
82+
prefix_roots: dict[str, list[Path]] = dataclasses.field(default_factory=dict)
8383
init_cache_file: Path = dataclasses.field(init=False, default=Path())
8484
env: dict[str, str] = dataclasses.field(init=False, default_factory=os.environ.copy)
8585
single_config: bool = not sysconfig.get_platform().startswith("win")
@@ -185,14 +185,14 @@ def init_cache(
185185
f.write('set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH" CACHE PATH "")\n')
186186

187187
if self.prefix_roots:
188-
for pkg, path in self.prefix_roots.items():
189-
path_str = str(path).replace("\\", "/")
188+
for pkg, path_list in self.prefix_roots.items():
189+
paths_str = ";".join(map(str, path_list)).replace("\\", "/")
190190
f.write(
191-
f'set({pkg}_ROOT [===[{path_str}]===] CACHE PATH "" FORCE)\n'
191+
f'set({pkg}_ROOT [===[{paths_str}]===] CACHE PATH "" FORCE)\n'
192192
)
193193
# Available since CMake 3.27 with CMP0144
194194
f.write(
195-
f'set({pkg.upper()}_ROOT [===[{path_str}]===] CACHE PATH "" FORCE)\n'
195+
f'set({pkg.upper()}_ROOT [===[{paths_str}]===] CACHE PATH "" FORCE)\n'
196196
)
197197

198198
contents = self.init_cache_file.read_text(encoding="utf-8").strip()

src/scikit_build_core/settings/skbuild_model.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,19 @@ class SearchSettings:
9393
Add the wheel build path to the CMake prefix paths.
9494
"""
9595

96-
modules: Optional[Union[List[Path], Dict[str, Path]]] = None
96+
modules: Optional[Union[List[str], Dict[str, str]]] = None
9797
"""
9898
List or dict of CMake module search paths. Dict from is used to override
9999
another package's entry-point definition. Populates `CMAKE_MODULE_PATH`.
100100
"""
101101

102-
prefixes: Optional[Union[List[Path], Dict[str, Path]]] = None
102+
prefixes: Optional[Union[List[str], Dict[str, str]]] = None
103103
"""
104104
List or dict of CMake prefix search paths. Dict from is used to override
105105
another package's entry-point definition. Populates `CMAKE_PREFIX_PATH`.
106106
"""
107107

108-
roots: Dict[str, Path] = dataclasses.field(default_factory=dict)
108+
roots: Dict[str, str] = dataclasses.field(default_factory=dict)
109109
"""
110110
Dict of package names and prefix paths. Populates `<Pkg>_ROOT`.
111111
"""

0 commit comments

Comments
 (0)