55import hashlib
66import importlib .resources as pkg_resources
77from abc import ABC , abstractmethod
8- from collections .abc import Callable
8+ from collections .abc import Callable , Iterable
99from functools import partial
1010from os import PathLike
1111from pathlib import Path
@@ -65,7 +65,7 @@ def files(self) -> dict:
6565 @abstractmethod
6666 def models (self ) -> dict :
6767 """
68- A map of model name to the model's input file set .
68+ A map of model name to the model's input files .
6969 """
7070 ...
7171
@@ -102,7 +102,11 @@ class LocalRegistry(ModelRegistry):
102102
103103 exclude : ClassVar = [".DS_Store" , "compare" ]
104104
105- def __init__ (self , path : str | PathLike , namefile_pattern : str = "mfsim.nam" ):
105+ def __init__ (
106+ self ,
107+ path : str | PathLike | Iterable [str | PathLike ],
108+ namefile_pattern : str = "mfsim.nam" ,
109+ ):
106110 """
107111 Create a registry from models under the given
108112 directory path.
@@ -112,12 +116,23 @@ def __init__(self, path: str | PathLike, namefile_pattern: str = "mfsim.nam"):
112116 are identified by the presence of a namefile
113117 matching `namefile_pattern`.
114118 """
115- self ._path = Path (path ).expanduser ().resolve ().absolute ()
119+ # check if path is iterable of str\pathlike
120+ if isinstance (path , Iterable ) and not isinstance (path , str ):
121+ path = [Path (p ).expanduser ().resolve ().absolute () for p in path ]
122+ missing = [p for p in path if not p .is_dir ()]
123+ if any (missing ):
124+ raise NotADirectoryError (
125+ f"Directory paths not found: { ', ' .join (missing )} "
126+ )
127+ self ._path = path
128+ else :
129+ path = Path (path ).expanduser ().resolve ().absolute ()
130+ if not path .is_dir ():
131+ raise NotADirectoryError (f"Directory path not found: { path } " )
132+ self ._path = [path ]
116133 self ._files : dict [str , dict [str , str | None ]] = {}
117134 self ._models : dict [str , list [str ]] = {}
118135 self ._examples : dict [str , list [str ]] = {}
119- if not self ._path .is_dir ():
120- raise NotADirectoryError (f"Path { self ._path } is not a directory." )
121136 self .namefile_pattern = namefile_pattern
122137 self .index ()
123138
@@ -131,25 +146,28 @@ def index(self):
131146 self ._files = {}
132147 self ._models = {}
133148 self ._examples = {}
134- model_paths = get_model_paths (self ._path , namefile = self .namefile_pattern )
135- for model_path in model_paths :
136- model_path = model_path .expanduser ().resolve ().absolute ()
137- rel_path = model_path .relative_to (self ._path )
138- model_name = "/" .join (rel_path .parts )
139- self ._models [model_name ] = []
140- if len (rel_path .parts ) > 1 :
141- name = rel_path .parts [0 ]
142- if name not in self ._examples :
143- self ._examples [name ] = []
144- self ._examples [name ].append (model_name )
145- for p in model_path .rglob ("*" ):
146- if not p .is_file () or any (e in p .name for e in LocalRegistry .exclude ):
147- continue
148- relpath = p .expanduser ().absolute ().relative_to (self ._path )
149- name = "/" .join (relpath .parts )
150- hash = _sha256 (p )
151- self ._files [name ] = {"hash" : hash }
152- self ._models [model_name ].append (name )
149+ for path in self ._path :
150+ model_paths = get_model_paths (path , namefile = self .namefile_pattern )
151+ for model_path in model_paths :
152+ model_path = model_path .expanduser ().resolve ().absolute ()
153+ rel_path = model_path .relative_to (path )
154+ model_name = "/" .join (rel_path .parts )
155+ self ._models [model_name ] = []
156+ if len (rel_path .parts ) > 1 :
157+ name = rel_path .parts [0 ]
158+ if name not in self ._examples :
159+ self ._examples [name ] = []
160+ self ._examples [name ].append (model_name )
161+ for p in model_path .rglob ("*" ):
162+ if not p .is_file () or any (
163+ e in p .name for e in LocalRegistry .exclude
164+ ):
165+ continue
166+ relpath = p .expanduser ().absolute ().relative_to (path )
167+ name = "/" .join (relpath .parts )
168+ hash = _sha256 (p )
169+ self ._files [name ] = {"hash" : hash , "path" : p , "relpath" : relpath }
170+ self ._models [model_name ].append (p )
153171
154172 def copy_to (
155173 self , workspace : str | PathLike , model_name : str , verbose : bool = False
@@ -159,7 +177,7 @@ def copy_to(
159177 The workspace will be created if it does not exist.
160178 """
161179
162- if not any (files := self .models .get (model_name , [])):
180+ if not any (file_paths := self .models .get (model_name , [])):
163181 return None
164182 # create the workspace if needed
165183 workspace = Path (workspace ).expanduser ().absolute ()
@@ -169,13 +187,13 @@ def copy_to(
169187 # copy the files. some might be in nested folders,
170188 # but the first is guaranteed not to be, so use it
171189 # to determine relative path in the new workspace.
172- base = Path (files [0 ]).parent
173- for file in [ Path ( self . _path ) / f for f in files ] :
190+ base = Path (file_paths [0 ]).parent
191+ for file_path in file_paths :
174192 if verbose :
175- print (f"Copying { file } to workspace" )
176- path = workspace / file .relative_to (base )
177- path .parent .mkdir (parents = True , exist_ok = True )
178- copy (file , workspace / file . relative_to ( base ) )
193+ print (f"Copying { file_path } to workspace" )
194+ dest = workspace / file_path .relative_to (base )
195+ dest .parent .mkdir (parents = True , exist_ok = True )
196+ copy (file_path , dest )
179197 return workspace
180198
181199 @property
0 commit comments