11import click
22import os
33
4- _UNNAMED_STORES = ['snapshots' , 'trajectories' , 'samples' , 'sample_sets' ,
5- 'steps' ]
6-
74
85class AbstractParameter (object ):
6+ """Abstract wrapper for click parameters.
7+
8+ Forbids use setting ``required``, because we do that for each command
9+ individually.
10+
11+ Parameters
12+ ----------
13+ args :
14+ args to pass to click parameters
15+ kwargs :
16+ kwargs to pass to click parameters
17+ """
918 def __init__ (self , * args , ** kwargs ):
1019 self .args = args
1120 if 'required' in kwargs :
@@ -15,32 +24,57 @@ def __init__(self, *args, **kwargs):
1524 def clicked (self , required = False ):
1625 raise NotImplementedError ()
1726
27+
1828HELP_MULTIPLE = "; may be used more than once"
1929
30+
2031# we'll use tests of the -h option in the .travis.yml to ensure that the
2132# .clicked methods work
2233class Option (AbstractParameter ):
34+ """Wrapper for click.option decorators"""
2335 def clicked (self , required = False ): # no-cov
36+ """Create the click decorator"""
2437 return click .option (* self .args , ** self .kwargs , required = required )
2538
39+
2640class Argument (AbstractParameter ):
41+ """Wrapper for click.argument decorators"""
2742 def clicked (self , required = False ): # no-cov
43+ """Create the click decorator"""
2844 return click .argument (* self .args , ** self .kwargs , required = required )
2945
3046
3147class AbstractLoader (object ):
48+ """Abstract object for getting relevant OPS object from the CLI.
49+
50+ Parameters
51+ ----------
52+ param : :class:`.AbstractParameter`
53+ the Option or Argument wrapping a click decorator
54+ """
3255 def __init__ (self , param ):
3356 self .param = param
3457
3558 @property
3659 def clicked (self ): # no-cov
60+ """Create the click decorator"""
3761 return self .param .clicked
3862
3963 def get (self , * args , ** kwargs ):
64+ """Get the desired OPS object, based on the CLI input"""
4065 raise NotImplementedError ()
4166
4267
4368class StorageLoader (AbstractLoader ):
69+ """Open an OPS storage file
70+
71+ Parameters
72+ ----------
73+ param : :class:`.AbstractParameter`
74+ the Option or Argument wrapping a click decorator
75+ mode : 'r', 'w', or 'a'
76+ the mode for the file
77+ """
4478 def __init__ (self , param , mode ):
4579 super (StorageLoader , self ).__init__ (param )
4680 self .mode = mode
@@ -61,12 +95,34 @@ def get(self, name):
6195
6296class OPSStorageLoadNames (AbstractLoader ):
6397 """Simple loader that expects its input to be a name or index.
98+
99+ Parameters
100+ ----------
101+ param : :class:`.AbstractParameter`
102+ the Option or Argument wrapping a click decorator
103+ store : Str
104+ the name of the store to search
64105 """
65106 def __init__ (self , param , store ):
66107 super (OPSStorageLoadNames , self ).__init__ (param )
67108 self .store = store
68109
69110 def get (self , storage , names ):
111+ """Get the names from the storage
112+
113+ Parameters
114+ ----------
115+ storage : :class:`openpathsampling.Storage`
116+ storage file to search in
117+ names : List[Str]
118+ names or numbers (as string) to use as keys to load from
119+ storage
120+
121+ Returns
122+ -------
123+ List[Any] :
124+ the desired objects
125+ """
70126 int_corrected = []
71127 for name in names :
72128 try :
@@ -80,6 +136,13 @@ def get(self, storage, names):
80136
81137
82138class Getter (object ):
139+ """Abstract strategy for getting things from storage
140+
141+ Parameters
142+ ----------
143+ store_name : Str
144+ the name of the storage to search
145+ """
83146 def __init__ (self , store_name ):
84147 self .store_name = store_name
85148
@@ -90,11 +153,15 @@ def _get(self, storage, name):
90153 except :
91154 return None
92155
156+
93157class GetByName (Getter ):
158+ """Strategy using the CLI input as name for a stored item"""
94159 def __call__ (self , storage , name ):
95160 return self ._get (storage , name )
96161
162+
97163class GetByNumber (Getter ):
164+ """Strategy using the CLI input as numeric index of the stored item"""
98165 def __call__ (self , storage , name ):
99166 try :
100167 num = int (name )
@@ -103,28 +170,36 @@ def __call__(self, storage, name):
103170
104171 return self ._get (storage , num )
105172
173+
106174class GetPredefinedName (Getter ):
175+ """Strategy predefining name and store, allow default names"""
107176 def __init__ (self , store_name , name ):
108177 super ().__init__ (store_name = store_name )
109178 self .name = name
110179
111180 def __call__ (self , storage ):
112181 return self ._get (storage , self .name )
113182
183+
114184class GetOnly (Getter ):
185+ """Strategy getting item from store if it is the only one"""
115186 def __call__ (self , storage ):
116187 store = getattr (storage , self .store_name )
117188 if len (store ) == 1 :
118189 return store [0 ]
119190
191+
120192class GetOnlyNamed (Getter ):
193+ """Strategy selecting item from store if it is the only named item"""
121194 def __call__ (self , storage ):
122195 store = getattr (storage , self .store_name )
123196 named_things = [o for o in store if o .is_named ]
124197 if len (named_things ) == 1 :
125198 return named_things [0 ]
126199
200+
127201class GetOnlySnapshot (Getter ):
202+ """Strategy selecting only snapshot from a snapshot store"""
128203 def __init__ (self , store_name = "snapshots" ):
129204 super ().__init__ (store_name )
130205
@@ -147,7 +222,24 @@ class OPSStorageLoadSingle(AbstractLoader):
147222 """Objects that expect to load a single object.
148223
149224 These can sometimes include guesswork to figure out which object is
150- desired.
225+ desired. The details of how that guesswork is performed is determined
226+ by the strategy lists that are given.
227+
228+ Parameters
229+ ----------
230+ param : :class:`.AbstractParameter`
231+ the Option or Argument wrapping a click decorator
232+ store : Str
233+ the name of the store to search
234+ value_strategies : List[Callable[(:class:`.Storage`, Str), Any]]
235+ The strategies to be used when the CLI provides a value for this
236+ parameter. Each should be a callable taking a storage and the string
237+ input from the CLI, and should return the desired object or None if
238+ it cannot be found.
239+ none_strategies : List[Callable[:class:`openpathsampling.Storage, Any]]
240+ The strategies to be used when the CLI does not provide a value for
241+ this parameter. Each should be a callable taking a storage, and
242+ returning the desired object or None if it cannot be found.
151243 """
152244 def __init__ (self , param , store , value_strategies = None ,
153245 none_strategies = None ):
@@ -164,9 +256,16 @@ def __init__(self, param, store, value_strategies=None,
164256 self .none_strategies = none_strategies
165257
166258 def get (self , storage , name ):
167- store = getattr (storage , self .store )
168- # num_store = getattr(storage, self.num_store)
169-
259+ """Load desired object from storage.
260+
261+ Parameters
262+ ----------
263+ storage : openpathsampling.Storage
264+ the input storage to search
265+ name : Str or None
266+ string from CLI providing the identifier (name or index) for
267+ this object; None if not provided
268+ """
170269 if name is not None :
171270 result = _try_strategies (self .value_strategies , storage ,
172271 name = name )
@@ -178,6 +277,7 @@ def get(self, storage, name):
178277
179278 return result
180279
280+
181281ENGINE = OPSStorageLoadSingle (
182282 param = Option ('-e' , '--engine' , help = "identifer for the engine" ),
183283 store = 'engines' ,
@@ -187,7 +287,6 @@ def get(self, storage, name):
187287SCHEME = OPSStorageLoadSingle (
188288 param = Option ('-m' , '--scheme' , help = "identifier for the move scheme" ),
189289 store = 'schemes' ,
190- # fallback=None
191290)
192291
193292INIT_CONDS = OPSStorageLoadSingle (
0 commit comments