7 This module is an implementation of eHive's Param module. 8 It defines ParamContainer which is an attribute of BaseRunnable 9 and not its base class as in eHive's class hierarchy. 10 All the specific warnings and exceptions inherit from ParamWarning 16 """Used by Process.BaseRunnable""" 20 class ParamException(Exception):
21 """Base class for parameters-related exceptions""" 24 """Raised when the parameter name is not a string""" 26 return '"{0}" (type {1}) is not a valid parameter name'.format(self.args[0], type(self.args[0]).__name__)
28 """Raised when ParamContainer tried to substitute an unexpected structure (only dictionaries and lists are accepted)""" 30 return 'Cannot substitute elements in objects of type "{0}"'.format(str(type(self.args[0])))
32 """Raised when parameters depend on each other, forming a loop""" 34 return "Substitution loop has been detected on {0}. Parameter-substitution stack: {1}".format(self.args[0], list(self.args[1].keys()))
36 """Raised when a parameter cannot be required because it is null (None)""" 38 return "{0} is None".format(self.args[0])
42 """Equivalent of eHive's Param module""" 44 def __init__(self, unsubstituted_params, debug=False):
45 """Constructor. "unsubstituted_params" is a dictionary""" 46 self.unsubstituted_param_hash = unsubstituted_params.copy()
55 """Setter. Returns the new value""" 62 """Getter. Performs the parameter substitution""" 68 except (KeyError, SyntaxError, ParamException)
as e:
70 raise type(e)(*e.args)
from None 73 """Returns a boolean. It checks both substituted and unsubstituted parameters""" 82 """Tells whether "param_name" is a non-empty string""" 83 return isinstance(param_name, str)
and (param_name !=
'')
86 """Print debug information if the debug flag is turned on (cf constructor)""" 88 print(*args, **kwargs)
91 """Equivalent of get_param() that assumes "param_name" is a valid parameter name and hence, doesn't have to raise ParamNameException. 92 It is only used internally""" 102 Take any structure and replace the pairs of hashes with the values of the parameters / expression they represent 103 Compatible types: numbers, strings, lists, dictionaries (otherwise, ParamSubstitutionException is raised) 107 if structure
is None:
110 elif isinstance(structure, list):
113 elif isinstance(structure, dict):
118 elif isinstance(structure, numbers.Number):
121 elif isinstance(structure, str):
125 if structure[:6] ==
'#expr(' and structure[-6:] ==
')expr#' and structure.count(
'#expr(', 6, -6) == 0
and structure.count(
')expr#', 6, -6) == 0:
128 if structure[0] ==
'#' and structure[-1] ==
'#' and structure.count(
'#', 1, -1) == 0:
129 if len(structure) <= 2:
142 Parse "structure" and replace all the pairs of hashes by the result of calling callback() on the pair content 143 #expr()expr# are treated differently by calling subst_one_hashpair() 144 The result is a string (like structure) 149 (head,_,tmp) = structure.partition(
'#')
152 return ''.join(result)
153 if tmp.startswith(
'expr('):
154 i = tmp.find(
')expr#')
156 raise SyntaxError(
"Unmatched '#expr(' token")
160 (middle_param,_,tail) = tmp.partition(
'#')
162 raise SyntaxError(
"Unmatched '#' token")
163 if middle_param ==
'':
166 val = callback(middle_param)
167 result.append(str(val))
173 Run the parameter substitution for a single pair of hashes. 174 Here, we only need to handle #expr()expr#, #func:params# and #param_name# 175 as each condition has been parsed in the other methods 177 self.
debug_print(
"subst_one_hashpair", inside_hashes, is_expr)
186 s = self.
subst_all_hashpairs(inside_hashes[5:-5].strip(),
lambda middle_param:
'self.internal_get_param("{0}")'.format(middle_param))
189 elif ':' in inside_hashes:
190 (func_name,_,parameters) = inside_hashes.partition(
':')
194 raise SyntaxError(
"Unknown method: " + func_name)
201 raise SyntaxError(func_name +
" is not callable")
215 (
'delta' ,
'#expr( #alpha#*#beta# )expr#'),
217 (
'gamma' , [10,20,33,15]),
218 (
'gamma_prime' ,
'#expr( #gamma# )expr#'),
219 (
'gamma_second' ,
'#expr( list(#gamma#) )expr#'),
221 (
'age' , {
'Alice' : 17,
'Bob' : 20,
'Chloe' : 21}),
222 (
'age_prime' ,
'#expr( #age# )expr#'),
223 (
'age_second' ,
'#expr( dict(#age#) )expr#'),
225 (
'csv' ,
'[123,456,789]'),
226 (
'csv_prime' ,
'#expr( #csv# )expr#'),
227 (
'listref' ,
'#expr( eval(#csv#) )expr#'),
230 (
'ref_null' ,
'#null#'),
231 (
'ref2_null' ,
'#expr( #null# )expr#'),
232 (
'ref3_null' ,
'#alpha##null##beta#'),
237 def print_title(title):
239 print(
"*" + title +
"*")
241 def print_substitution(title, param_string):
243 print(
"\t>", param_string)
244 x = p.param_substitute(param_string)
247 def print_param_value(x):
248 print(
"\t=", x, type(x),
"id=0x{0:012x}".format(id(x)))
250 print_title(
"Exceptions")
252 p.get_param(
'ppppppp')
253 except KeyError
as e:
254 print(
"KeyError raised")
256 print(
"KeyError NOT raised")
261 except ParamNameException
as e:
262 print(
"ParamNameException raised")
264 print(
"ParamNameException NOT raised")
269 except ParamInfiniteLoopException
as e:
270 print(
"ParamInfiniteLoopException raised")
272 print(
"ParamInfiniteLoopException NOT raised")
275 print_title(
'All the parameters')
276 for (key,value)
in seed_params:
277 print(
"\t>", key,
"is seeded as:", value, type(value))
282 print_title(
"Numbers")
283 print_substitution(
"Scalar substitutions",
"#alpha# and another: #beta# and again one: #alpha# and the other: #beta# . Their product: #delta#" )
286 print_substitution(
"default stringification of gamma",
"#gamma#" )
287 print_substitution(
"expr-stringification of gamma",
"#expr( #gamma# )expr#" )
288 print_substitution(
"complex join of gamma",
"#expr( '~'.join([str(_) for _ in sorted(#gamma#)]) )expr#" )
289 print_substitution(
"complex join of gamma_prime",
"#expr( '~'.join([str(_) for _ in sorted(#gamma_prime#)]) )expr#" )
291 print_title(
"Global methods")
292 print_substitution(
"sum(gamma)",
"#expr( sum(#gamma#) )expr#" )
293 print_substitution(
"min(gamma)",
"#expr( min(#gamma#) )expr#" )
294 print_substitution(
"max(gamma)",
"#expr( max(#gamma#) )expr#" )
296 print_title(
"Dictionaries")
297 print_substitution(
"default stringification of age",
"#age#" )
298 print_substitution(
"expr-stringification of age",
"#expr( #age# )expr#" )
299 print_substitution(
"complex fold of age",
'#expr( "\t".join(["{0} is {1} years old".format(p,a) for (p,a) in #age#.items()]) )expr#' )
300 print_substitution(
"complex fold of age_prime",
'#expr( "\t".join(["{0} is {1} years old".format(p,a) for (p,a) in #age_prime#.items()]) )expr#' )
302 print_title(
"With indexes")
303 print_substitution(
"adding indexed values",
'#expr( #age#["Alice"]+max(#gamma#)+#listref#[0] )expr#' )
305 print_title(
"Modifications of gamma")
306 p.get_param(
'gamma').append(
"val0")
307 print(
"\tgamma", p.get_param(
'gamma'))
308 print(
"\tgamma_prime", p.get_param(
'gamma_prime'))
309 print(
"\tgamma_second", p.get_param(
'gamma_second'))
312 if __name__ ==
'__main__':
Base class for parameters-related exceptions.
Raised when ParamContainer tried to substitute an unexpected structure (only dictionaries and lists a...
def validate_parameter_name(self, param_name)
Tells whether "param_name" is a non-empty string.
def subst_all_hashpairs(self, structure, callback)
Parse "structure" and replace all the pairs of hashes by the result of calling callback() on the pair...
def get_param(self, param_name)
Getter.
def debug_print(self, args, kwargs)
Print debug information if the debug flag is turned on (cf constructor)
def internal_get_param(self, param_name)
Equivalent of get_param() that assumes "param_name" is a valid parameter name and hence...
Equivalent of eHive's Param module.
def has_param(self, param_name)
Returns a boolean.
def subst_one_hashpair(self, inside_hashes, is_expr)
Run the parameter substitution for a single pair of hashes.
Raised when a parameter cannot be required because it is null (None)
def set_param(self, param_name, value)
Setter.
Used by Process.BaseRunnable.
Raised when the parameter name is not a string.
def param_substitute(self, structure)
Take any structure and replace the pairs of hashes with the values of the parameters / expression the...
Raised when parameters depend on each other, forming a loop.