Skip to content

Commit 087b063

Browse files
authored
refactor(LocalRegistry): back to the old indexing pattern (#214)
Sometimes you end up right where you started, a bit wiser for your travails
1 parent aa62b34 commit 087b063

1 file changed

Lines changed: 42 additions & 59 deletions

File tree

modflow_devtools/models.py

Lines changed: 42 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import hashlib
66
import importlib.resources as pkg_resources
77
from abc import ABC, abstractmethod
8-
from collections.abc import Callable, Iterable
8+
from collections.abc import Callable
99
from functools import partial
1010
from os import PathLike
1111
from pathlib import Path
@@ -96,73 +96,56 @@ class LocalRegistry(ModelRegistry):
9696

9797
exclude: ClassVar = [".DS_Store", "compare"]
9898

99-
def __init__(
99+
def __init__(self) -> None:
100+
self._paths: set[Path] = set()
101+
self._files: dict[str, Path] = {}
102+
self._models: dict[str, list[Path]] = {}
103+
self._examples: dict[str, list[str]] = {}
104+
105+
def index(
100106
self,
101-
path: str | PathLike | Iterable[str | PathLike],
102-
namefile_pattern: str = "mfsim.nam",
107+
path: str | PathLike,
108+
prefix: str = "",
109+
namefile: str = "mfsim.nam",
103110
):
104111
"""
105-
Create a registry from models under the given
106-
directory path.
112+
Add models found under the given path to the registry.
113+
114+
Call this once or more to prepare a registry. If called on the same
115+
`path` again, the models will be reloaded — thus this method
116+
is idempotent and may be used to reload the registry e.g. if model
117+
files have changed since the registry was created.
107118
108119
The `path` may consist of model subdirectories
109120
at arbitrary depth. Model input subdirectories
110121
are identified by the presence of a namefile
111122
matching `namefile_pattern`.
112123
"""
113-
# check if path is iterable of str\pathlike
114-
if isinstance(path, Iterable) and not isinstance(path, str):
115-
path = [Path(p).expanduser().resolve().absolute() for p in path] # type: ignore
116-
missing = [p for p in path if not p.is_dir()] # type: ignore
117-
if any(missing):
118-
missing = [str(p) for p in missing] # type: ignore
119-
raise NotADirectoryError(
120-
f"Directory paths not found: {', '.join(missing)}" # type: ignore
121-
)
122-
self._path = path
123-
else:
124-
path = Path(path).expanduser().resolve().absolute()
125-
if not path.is_dir():
126-
raise NotADirectoryError(f"Directory path not found: {path}")
127-
self._path = [path]
128-
self._files: dict[str, dict[str, str | None]] = {}
129-
self._models: dict[str, list[str]] = {}
130-
self._examples: dict[str, list[str]] = {}
131-
self.namefile_pattern = namefile_pattern
132-
self.index()
133124

134-
def index(self):
135-
"""
136-
Build the registry from models found under the configured path. This
137-
method can be called to reload the registry e.g. if model files have
138-
changed since the registry was created.
139-
"""
125+
path = Path(path).expanduser().resolve().absolute()
126+
if not path.is_dir():
127+
raise NotADirectoryError(f"Directory path not found: {path}")
128+
self._paths.add(path)
140129

141-
self._files = {}
142-
self._models = {}
143-
self._examples = {}
144-
for path in self._path:
145-
model_paths = get_model_paths(path, namefile=self.namefile_pattern)
146-
for model_path in model_paths:
147-
model_path = model_path.expanduser().resolve().absolute()
148-
rel_path = model_path.relative_to(path)
149-
model_name = "/".join(rel_path.parts)
150-
self._models[model_name] = []
151-
if len(rel_path.parts) > 1:
152-
name = rel_path.parts[0]
153-
if name not in self._examples:
154-
self._examples[name] = []
155-
self._examples[name].append(model_name)
156-
for p in model_path.rglob("*"):
157-
if not p.is_file() or any(
158-
e in p.name for e in LocalRegistry.exclude
159-
):
160-
continue
161-
relpath = p.expanduser().absolute().relative_to(path)
162-
name = "/".join(relpath.parts)
163-
hash = _sha256(p)
164-
self._files[name] = {"hash": hash, "path": p, "relpath": relpath}
165-
self._models[model_name].append(p)
130+
model_paths = get_model_paths(path, namefile=namefile)
131+
for model_path in model_paths:
132+
model_path = model_path.expanduser().resolve().absolute()
133+
rel_path = model_path.relative_to(path)
134+
parts = [prefix, *list(rel_path.parts)] if prefix else list(rel_path.parts)
135+
model_name = "/".join(parts)
136+
self._models[model_name] = []
137+
if len(rel_path.parts) > 1:
138+
name = rel_path.parts[0]
139+
if name not in self._examples:
140+
self._examples[name] = []
141+
self._examples[name].append(model_name)
142+
for p in model_path.rglob("*"):
143+
if not p.is_file() or any(e in p.name for e in LocalRegistry.exclude):
144+
continue
145+
relpath = p.expanduser().absolute().relative_to(path)
146+
name = "/".join(relpath.parts)
147+
self._files[name] = p
148+
self._models[model_name].append(p)
166149

167150
def copy_to(
168151
self, workspace: str | PathLike, model_name: str, verbose: bool = False
@@ -192,8 +175,8 @@ def copy_to(
192175
return workspace
193176

194177
@property
195-
def path(self) -> list[Path]:
196-
return self._path # type: ignore
178+
def paths(self) -> set[Path]:
179+
return self._paths
197180

198181
@property
199182
def files(self) -> dict:

0 commit comments

Comments
 (0)