11"""
22Classes to find data files and executables in global paths.
33"""
4+
45from abc import ABC , abstractmethod
56from collections .abc import Iterator , Iterable
67import os
1516else :
1617 EXE_SUFFIX = "sh"
1718
19+
1820class ResourceNotFound (RuntimeError ):
1921 pass
2022
23+
2124class AbstractResolver (ABC ):
2225 """
2326 Interface for resolvers.
@@ -26,6 +29,7 @@ class AbstractResolver(ABC):
2629 type. Implementations should pick a single type to yield, e.g. :class:`.ResourceResolver` always yields absolute
2730 paths, while :class:`.ExecutableResolver` always yields 2-tuples of a version tag and absolute paths.
2831 """
32+
2933 @abstractmethod
3034 def _search (self , name : tuple [str ]) -> Iterator [Any ]:
3135 pass
@@ -122,7 +126,9 @@ class ResolverChain(AbstractResolver):
122126 """
123127 A chain of resolvers. Matches are returned sequentially.
124128 """
129+
125130 __slots__ = ("_resolvers" ,)
131+
126132 def __init__ (self , * resolvers ):
127133 """
128134 Args:
@@ -136,7 +142,7 @@ def _search(self, name):
136142
137143 def __repr__ (self ):
138144 inner = ", " .join (repr (r ) for r in self ._resolvers )
139- return f' { type (self ).__name__ } ({ inner } )'
145+ return f" { type (self ).__name__ } ({ inner } )"
140146
141147
142148class ResourceResolver (AbstractResolver ):
@@ -158,7 +164,9 @@ class ResourceResolver(AbstractResolver):
158164 "potentials.csv"
159165 ]
160166 """
167+
161168 __slots__ = "_resource_paths" , "_module" , "_subdirs"
169+
162170 def __init__ (self , resource_paths , module , * subdirs ):
163171 """
164172 Args:
@@ -209,7 +217,9 @@ class ExecutableResolver(AbstractResolver):
209217 'v1_mpi': '/my/resources/lammps/bin/run_lammps_v1_mpi.sh)
210218 }
211219 """
220+
212221 __slots__ = "_regex" , "_resolver"
222+
213223 def __init__ (self , resource_paths , code , module = None , suffix = EXE_SUFFIX ):
214224 """
215225 Args:
@@ -223,10 +233,11 @@ def __init__(self, resource_paths, code, module=None, suffix=EXE_SUFFIX):
223233 if module is None :
224234 module = code
225235 self ._regex = re .compile (f"run_{ code } _(.*)\\ .{ suffix } $" )
226- self ._glob = f' run_{ code } _*.{ suffix } '
236+ self ._glob = f" run_{ code } _*.{ suffix } "
227237 self ._resolver = ResourceResolver (
228238 resource_paths ,
229- module , 'bin' ,
239+ module ,
240+ "bin" ,
230241 )
231242
232243 def __repr__ (self ):
@@ -239,10 +250,14 @@ def __repr__(self):
239250
240251 def _search (self , name ):
241252 seen = set ()
253+
242254 def cond (path ):
243255 isfile = os .path .isfile (path )
244- isexec = os .access (path , os .X_OK , effective_ids = os .access in os .supports_effective_ids )
256+ isexec = os .access (
257+ path , os .X_OK , effective_ids = os .access in os .supports_effective_ids
258+ )
245259 return isfile and isexec
260+
246261 for path in filter (cond , self ._resolver .search (self ._glob )):
247262 # we know that the regex has to match, because we constrain the resolver with the glob
248263 version = self ._regex .search (path ).group (1 )
0 commit comments