comparison configuration/configuration.py @ 133:f01d351ccf2b

STUB: configuration/configuration.py
author Jeff Hammel <k0scist@gmail.com>
date Sun, 30 Mar 2014 19:53:20 -0700
parents dff886188b55
children
comparison
equal deleted inserted replaced
132:af5e83a4763b 133:f01d351ccf2b
168 if value.get('default'): 168 if value.get('default'):
169 kw['action'] = 'store_false' 169 kw['action'] = 'store_false'
170 if not flags: 170 if not flags:
171 args = ['--no-%s' % name] 171 args = ['--no-%s' % name]
172 if not help: 172 if not help:
173 kw['help'] = 'disable %s' % name 173 kw['help'] = 'disable {}'.format(name)
174 else: 174 else:
175 kw['action'] = 'store_true' 175 kw['action'] = 'store_true'
176 if not help: 176 if not help:
177 kw['help'] = 'enable %s' % name 177 kw['help'] = 'enable {}'.format(name)
178 return args, kw 178 return args, kw
179
179 180
180 class ListCLI(BaseCLI): 181 class ListCLI(BaseCLI):
181 182
182 def __call__(self, name, value): 183 def __call__(self, name, value):
183 args, kw = BaseCLI.__call__(self, name, value) 184 args, kw = BaseCLI.__call__(self, name, value)
184
185 # TODO: could use 'extend'
186 # - http://hg.mozilla.org/build/mozharness/file/5f44ba08f4be/mozharness/base/config.py#l41
187
188 kw['action'] = 'append' 185 kw['action'] = 'append'
189 return args, kw 186 return args, kw
190 187
191 class IntCLI(BaseCLI): 188 class IntCLI(BaseCLI):
192 189
219 def take_action(self, value): 216 def take_action(self, value):
220 if self.delimeter not in value: 217 if self.delimeter not in value:
221 raise AssertionError("Each value must be delimited by '%s': %s" % (self.delimeter, value)) 218 raise AssertionError("Each value must be delimited by '%s': %s" % (self.delimeter, value))
222 return value.split(self.delimeter, 1) 219 return value.split(self.delimeter, 1)
223 220
221 # types of CLI arguments
224 types = {bool: BoolCLI(), 222 types = {bool: BoolCLI(),
225 int: IntCLI(), 223 int: IntCLI(),
226 float: FloatCLI(), 224 float: FloatCLI(),
227 list: ListCLI(), 225 list: ListCLI(),
228 dict: DictCLI(), 226 dict: DictCLI(),
229 str: BaseCLI(), 227 str: BaseCLI(),
230 None: BaseCLI()} # default 228 None: BaseCLI()} # default
231 229
232 __all__ += [i.__class__.__name__ for i in types.values()] 230 __all__ += [i.__class__.__name__ for i in types.values()]
233 231
232
234 class Configuration(optparse.OptionParser): 233 class Configuration(optparse.OptionParser):
235 """declarative configuration object""" 234 """declarative configuration object"""
236 235
237 options = {} # configuration basis definition 236 options = {} # configuration basis definition
238 extend = set() # which dicts/lists should be extended 237 extend = set() # which dicts/lists should be extended
249 def __init__(self, configuration_providers=configuration_providers, types=types, load=None, dump='--dump', **parser_args): 248 def __init__(self, configuration_providers=configuration_providers, types=types, load=None, dump='--dump', **parser_args):
250 249
251 # sanity check 250 # sanity check
252 if isinstance(self.options, dict): 251 if isinstance(self.options, dict):
253 self.option_dict = self.options 252 self.option_dict = self.options
254 elif isinstance(self.options, list): 253 elif isinstance(self.options, (list, tuple)):
255 # XXX could also be tuple, etc
256 self.option_dict = dict(self.options) 254 self.option_dict = dict(self.options)
257 else: 255 else:
258 raise NotImplementedError 256 raise NotImplementedError("Configuration: `options` should be castable to a dict")
259 257
260 # setup configuration 258 # setup configuration
261 self.config = {} 259 self.config = {}
262 self.configuration_providers = configuration_providers 260 self.configuration_providers = configuration_providers
263 self.types = types 261 self.types = types
294 dump = list(dump) 292 dump = list(dump)
295 self.add_option(*dump, **dict(dest='dump', 293 self.add_option(*dump, **dict(dest='dump',
296 help="Output configuration file; Formats: %s" % formats)) 294 help="Output configuration file; Formats: %s" % formats))
297 295
298 296
299 ### methods for iteration 297 ### iteration
300 ### TODO: make the class a real iterator
301 298
302 def items(self): 299 def items(self):
300 """items in options"""
301 # TODO: make the class a real iterator
302
303 # allow options to be a list of 2-tuples 303 # allow options to be a list of 2-tuples
304 if isinstance(self.options, dict): 304 if isinstance(self.options, dict):
305 return self.options.items() 305 return self.options.items()
306 return self.options 306 return self.options
307 307
313 """ 313 """
314 314
315 # ensure options in configuration are in self.options 315 # ensure options in configuration are in self.options
316 unknown_options = [i for i in config if i not in self.option_dict] 316 unknown_options = [i for i in config if i not in self.option_dict]
317 if unknown_options: 317 if unknown_options:
318 raise UnknownOptionException("Unknown options: %s" % ', '.join(unknown_options)) 318 raise UnknownOptionException("Unknown options: {}".format(', '.join(unknown_options)))
319 319
320 # ensure options are of the right type (if specified) 320 # ensure options are of the right type (if specified)
321 for key, value in config.items(): 321 for key, value in config.items():
322 _type = self.option_dict[key].get('type') 322 _type = self.option_dict[key].get('type')
323 if _type is None and 'default' in self.option_dict[key]: 323 if _type is None and 'default' in self.option_dict[key]:
332 pass 332 pass
333 if tocast: 333 if tocast:
334 try: 334 try:
335 config[key] = _type(value) 335 config[key] = _type(value)
336 except BaseException, e: 336 except BaseException, e:
337 raise TypeCastException("Could not coerce %s, %s, to type %s: %s" % (key, value, _type.__name__, e)) 337 raise TypeCastException("Could not coerce '%s'=%s, to type %s: %s" % (key, value, _type.__name__, e))
338 338
339 return config 339 return config
340 340
341 def validate(self): 341 def validate(self):
342 """validate resultant configuration""" 342 """validate resultant configuration"""
346 required = value.get('required') 346 required = value.get('required')
347 if required: 347 if required:
348 if isinstance(required, basestring): 348 if isinstance(required, basestring):
349 required_message = required 349 required_message = required
350 else: 350 else:
351 required_message = "Parameter %s is required but not present" % key 351 required_message = "Parameter {} is required but not present".format(key)
352 # TODO: this should probably raise all missing values vs 352 # TODO: this should probably raise all missing values vs
353 # one by one 353 # one by one
354 raise MissingValueException(required_message) 354 raise MissingValueException(required_message)
355 # TODO: configuration should be locked after this is called 355
356 356
357 ### methods for adding configuration 357 ### methods for adding configuration
358 358
359 def default_config(self): 359 def default_config(self):
360 """configuration defaults""" 360 """configuration defaults"""
370 def __getitem__(self, key): 370 def __getitem__(self, key):
371 return self.config[key] 371 return self.config[key]
372 372
373 def __call__(self, *args): 373 def __call__(self, *args):
374 """add items to configuration and check it""" 374 """add items to configuration and check it"""
375 # TODO: configuration should be locked after this is called
376 375
377 # start with defaults 376 # start with defaults
378 self.config = self.default_config() 377 self.config = self.default_config()
379 378
380 # add the configuration 379 # add the configuration
426 if 'type' in value: 425 if 'type' in value:
427 return value['type'] 426 return value['type']
428 if 'default' in value: 427 if 'default' in value:
429 default = value['default'] 428 default = value['default']
430 if default is None: 429 if default is None:
431 return None 430 return None # not <type 'NoneType'>
432 return type(value['default']) 431 return type(value['default'])
433 432
434 def optparse_options(self, parser): 433 def optparse_options(self, parser):
435 """add optparse options to a OptionParser instance""" 434 """add optparse options to a OptionParser instance"""
436 for key, value in self.items(): 435 for key, value in self.items():
518 dump = getattr(options, 'dump') 517 dump = getattr(options, 'dump')
519 if dump: 518 if dump:
520 # TODO: have a way of specifying format other than filename 519 # TODO: have a way of specifying format other than filename
521 self.serialize(dump) 520 self.serialize(dump)
522 521
522
523 ### serialization/deserialization 523 ### serialization/deserialization
524 524
525 def formats(self): 525 def formats(self):
526 """formats for deserialization""" 526 """formats for deserialization"""
527 retval = [] 527 retval = []