Source code for iceprod.core.dataclasses

"""
A set of classes that holds dataset configuration data.

Each class is based on a dictionary and only contains simple elements for
easy serialization to json (or other formats). A full dataset configuration
can be had by serializing the :class:`Job` class.

The `convert` method of each class will turn any regular dictionary objects
into special `dataclasses` objects.

The `valid` method of each class will test the validity of the data to be
an actual dataset config.

The `output` method of each class will create json with info on each
dataclass, to be used in javascript.
"""

from __future__ import absolute_import, division, print_function

import time

from numbers import Number, Integral
try:
    String = basestring
except NameError:
    String = str

# pluralizations for keys that are not classes here
_plurals = {
    'Option': 'Options',
    'Category': 'Categories',
    'Parameter': 'Parameters',
    'System': 'System',
    'Dependence': 'Depends'
}


[docs] class Job(dict): """ Holds all information about a running job. If the `options` are empty, this is the same as a dataset configuration. :ivar version: 3 :ivar options: {} -- a dict of parameters to pass to the task runner :ivar steering: None :ivar tasks: [] :ivar difplus: None :ivar description: "" :ivar categories: [] """ plural = 'Jobs' def __init__(self,*args,**kwargs): self['version'] = 3 self['options'] = {} self['steering'] = None self['tasks'] = [] self['difplus'] = None self['description'] = '' self['categories'] = [] super(Job,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'tasks': ret[n] = [self[n],'Task'] elif n == 'difplus': ret[n] = [self[n],'DifPlus'] elif n == 'steering': ret[n] = [self[n],'Steering'] elif n == 'categories': ret[n] = [self[n],''] else: ret[n] = self[n] return ret
[docs] def convert(self): if (self['steering'] is not None and not isinstance(self['steering'],Steering)): tmp = Steering(self['steering']) tmp.convert() self['steering'] = tmp for i,t in enumerate(self['tasks']): if not isinstance(t,Task): tmp = Task(t) tmp.convert() self['tasks'][i] = tmp if (self['difplus'] is not None and not isinstance(self['difplus'],DifPlus)): tmp = DifPlus(self['difplus']) tmp.convert() self['difplus'] = tmp
[docs] def valid(self): try: return ( isinstance(self['version'],Number) and self['version'] >= 3 and isinstance(self['options'],dict) and (self['steering'] is None or ( isinstance(self['steering'],Steering) and self['steering'].valid())) and isinstance(self['tasks'],list) and all(isinstance(t,Task) and t.valid() for t in self['tasks']) and (self['difplus'] is None or ( isinstance(self['difplus'],DifPlus) and self['difplus'].valid())) and isinstance(self['description'],String) and isinstance(self['categories'],list) ) except Exception: return False
[docs] class Steering(dict): """ Holds all information that goes in the steering section of a configuration. :ivar parameters: {} :ivar batchsys: None :ivar system: {} -- just specialized parameters :ivar resources: [] :ivar data: [] """ plural = 'Steering' def __init__(self,*args,**kwargs): self['parameters'] = {} self['batchsys'] = None self['system'] = {} self['resources'] = [] self['data'] = [] super(Steering,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'resources': ret[n] = [self[n],'Resource'] elif n == 'data': ret[n] = [self[n],'Data'] elif n == 'batchsys': ret[n] = [self[n],'Batchsys'] else: ret[n] = self[n] return ret
[docs] def convert(self): if (self['batchsys'] is not None and not isinstance(self['batchsys'],Batchsys)): tmp = Batchsys(self['batchsys']) tmp.convert() self['batchsys'] = tmp for i,r in enumerate(self['resources']): if not isinstance(r,Resource): tmp = Resource(r) tmp.convert() self['resources'][i] = tmp for i,d in enumerate(self['data']): if not isinstance(d,Data): tmp = Data(d) tmp.convert() self['data'][i] = tmp
[docs] def valid(self): try: return ( isinstance(self['parameters'],dict) and (self['batchsys'] is None or ( isinstance(self['batchsys'],Batchsys) and self['batchsys'].valid())) and isinstance(self['system'],dict) and isinstance(self['resources'],list) and all(isinstance(r,Resource) and r.valid() for r in self['resources']) and isinstance(self['data'],list) and all(isinstance(d,Data) and d.valid() for d in self['data']) ) except Exception: return False
class Batchsys(dict): """ Holds information for running on grid/cluster types. Designed as a dict of dicts, one for each grid/cluster type. """ plural = "Batchsys" def output(self): """Output dict with values and (optionally) the object name for new objects.""" return {'*':{}} def convert(self): pass def valid(self): try: return all(isinstance(v,dict) for v in self.values()) except Exception: return False
[docs] class _TaskCommon(dict): """ Holds common attributes used by task, tray, module. :ivar name: '' :ivar resources: [] :ivar data: [] :ivar classes: [] :ivar parameters: {} """ def __init__(self,*args,**kwargs): self['name'] = '' self['resources'] = [] self['data'] = [] self['classes'] = [] self['parameters'] = {} super(_TaskCommon,self).__init__(*args,**kwargs)
[docs] def convert(self): for i,r in enumerate(self['resources']): if not isinstance(r,Resource): tmp = Resource(r) tmp.convert() self['resources'][i] = tmp for i,d in enumerate(self['data']): if not isinstance(d,Data): tmp = Data(d) tmp.convert() self['data'][i] = tmp for i,c in enumerate(self['classes']): if not isinstance(c,Class): tmp = Class(c) tmp.convert() self['classes'][i] = tmp
[docs] def valid(self): try: return ( isinstance(self['name'],String) and isinstance(self['resources'],list) and all(isinstance(r,Resource) and r.valid() for r in self['resources']) and isinstance(self['data'],list) and all(isinstance(d,Data) and d.valid() for d in self['data']) and isinstance(self['classes'],list) and all(isinstance(c,Class) and c.valid() for c in self['classes']) and isinstance(self['parameters'],dict) ) except Exception: return False
class Requirement(dict): plural = 'Requirements' def __init__(self, *args,**kwargs): self['cpu'] = None self['gpu'] = None self['memory'] = None self['disk'] = None self['os'] = None self['site'] = None super(Requirement,self).__init__(*args,**kwargs) def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: ret[n] = self[n] return ret def convert(self): pass def valid(self): return ( (self['cpu'] is None or isinstance(self['cpu'],(String,Number))) and (self['gpu'] is None or isinstance(self['gpu'],(String,Number))) and (self['memory'] is None or isinstance(self['memory'],(String,Number))) and (self['disk'] is None or isinstance(self['disk'],(String,Number))) and (self['os'] is None or isinstance(self['os'],String)) and (self['site'] is None or isinstance(self['site'],String)) )
[docs] class Task(_TaskCommon): """ Holds all information about a task. :ivar depends: [] -- a list of task names :ivar batchsys: None :ivar trays: [] :ivar requirements: {} -- a dict of requirements :ivar task_files: False -- whether to use the task files API """ plural = 'Tasks' def __init__(self,*args,**kwargs): self['depends'] = [] self['batchsys'] = None self['trays'] = [] self['requirements'] = Requirement() self['task_files'] = False super(Task,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'resources': ret[n] = [self[n],'Resource'] elif n == 'data': ret[n] = [self[n],'Data'] elif n == 'classes': ret[n] = [self[n],'Class'] elif n == 'depends': ret[n] = [self[n],''] elif n == 'batchsys': ret[n] = [self[n],'Batchsys'] elif n == 'trays': ret[n] = [self[n],'Tray'] elif n == 'requirements': ret[n] = [self[n],'Requirement'] else: ret[n] = self[n] return ret
[docs] def convert(self): super(Task,self).convert() if (self['batchsys'] is not None and not isinstance(self['batchsys'],Batchsys)): tmp = Batchsys(self['batchsys']) tmp.convert() self['batchsys'] = tmp for i,t in enumerate(self['trays']): if not isinstance(t,Tray): tmp = Tray(t) tmp.convert() self['trays'][i] = tmp
[docs] def valid(self): try: return ( super(Task,self).valid() and isinstance(self['depends'],list) and all(isinstance(r,(String,Number)) for r in self['depends']) and (self['batchsys'] is None or ( isinstance(self['batchsys'],Batchsys) and self['batchsys'].valid())) and isinstance(self['trays'],list) and all(isinstance(t,Tray) and t.valid() for t in self['trays']) and isinstance(self['requirements'],Requirement) and self['requirements'].valid() and isinstance(self['task_files'],bool) ) except Exception: return False
[docs] class Tray(_TaskCommon): """ Holds all information about a tray. :ivar iterations: 1 :ivar modules: [] """ plural = 'Trays' def __init__(self,*args,**kwargs): self['iterations'] = 1 self['modules'] = [] super(Tray,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'resources': ret[n] = [self[n],'Resource'] elif n == 'data': ret[n] = [self[n],'Data'] elif n == 'classes': ret[n] = [self[n],'Class'] elif n == 'modules': ret[n] = [self[n],'Module'] else: ret[n] = self[n] return ret
[docs] def convert(self): super(Tray,self).convert() for i,m in enumerate(self['modules']): if not isinstance(m,Module): tmp = Module(m) tmp.convert() self['modules'][i] = tmp
[docs] def valid(self): try: return ( super(Tray,self).valid() and isinstance(self['iterations'],Integral) and isinstance(self['modules'],list) and all(isinstance(m,Module) and m.valid() for m in self['modules']) ) except Exception: return False
[docs] class Module(_TaskCommon): """ Holds all information about a module. :ivar running_class: None -- the python class or function to call :ivar src: None -- src of class or script :ivar args: None -- args to give to class or src if not an iceprod module :ivar env_shell: None -- src of script which sets env and calls arg :ivar env_clear: True -- clear the env before calling the module (calls env_shell after clearing, if defined) :ivar configs: None -- any json config files that should be written (format is {filename: data}) Note that `env_clear` should be used carefully, as it wipes out any loaded classes. """ plural = 'Modules' def __init__(self,*args,**kwargs): self['running_class'] = '' self['src'] = '' self['args'] = '' self['env_shell'] = '' self['env_clear'] = True self['configs'] = {} super(Module,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'resources': ret[n] = [self[n],'Resource'] elif n == 'data': ret[n] = [self[n],'Data'] elif n == 'classes': ret[n] = [self[n],'Class'] else: ret[n] = self[n] return ret
[docs] def convert(self): super(Module,self).convert()
[docs] def valid(self): try: return ( super(Module,self).valid() and isinstance(self['running_class'],String) and isinstance(self['src'],String) and isinstance(self['env_shell'],String) and isinstance(self['env_clear'],bool) and isinstance(self['configs'],dict) ) except Exception: return False
[docs] class Class(dict): """ A class object, downloaded from a url. :ivar name: None -- required :ivar src: None -- if downloaded from url :ivar resource_name: None -- if present in resource object :ivar recursive: False :ivar libs: None -- if more than default lib directory :ivar env_vars: None """ plural = 'Classes' def __init__(self,*args,**kwargs): self['name'] = '' self['src'] = '' self['resource_name'] = '' self['recursive'] = False self['libs'] = '' self['env_vars'] = '' super(Class,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: ret[n] = self[n] return ret
[docs] def convert(self): pass
[docs] def valid(self): try: return ( isinstance(self['name'],String) and isinstance(self['src'],String) and isinstance(self['resource_name'],String) and isinstance(self['recursive'],bool) and isinstance(self['libs'],String) and isinstance(self['env_vars'],String) ) except Exception: return False
[docs] class _ResourceCommon(dict): """ Holds common attributes used by Resource and Data. :ivar remote: '' :ivar local: '' :ivar compression: False """ compression_options = [False,True,'none','gzip','gz','bzip','bz2','lzma'] def __init__(self,*args,**kwargs): self['remote'] = '' self['local'] = '' self['compression'] = False self['transfer'] = True super(_ResourceCommon,self).__init__(*args,**kwargs)
[docs] def convert(self): pass
[docs] def valid(self): try: return ( isinstance(self['remote'],String) and isinstance(self['local'],String) and self['compression'] in self.compression_options and isinstance(self['transfer'],(String,Number,bool)) ) except Exception: return False
[docs] def do_transfer(self): """ Test if we should actually transfer the file. """ ret = True if isinstance(self['transfer'], bool): ret = self['transfer'] elif isinstance(self['transfer'], String): t = self['transfer'].lower() if t in ('n','no','not','f','false'): ret = False elif t in ('m','maybe','exists') or t.startswith('if'): ret = 'maybe' elif isinstance(self['transfer'], Number): if self['transfer'] == 0: ret = False return ret
[docs] class Resource(_ResourceCommon): """ A resource object, representing a file to download. :ivar arch: None """ plural = 'Resources' def __init__(self,*args,**kwargs): self['arch'] = '' super(Resource,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'compression': ret[n] = [self[n],self.compression_options] ret[n] = self[n] return ret
[docs] def convert(self): super(Resource,self).convert()
[docs] def valid(self): try: return ( super(Resource,self).valid() and isinstance(self['arch'],String) ) except Exception: return False
[docs] class Data(_ResourceCommon): """ A data object, representing input and/or output of data. :ivar type: 'permanent' -- required :ivar movement: 'both' -- required """ plural = 'Data' type_options = ['permanent','tray_temp','task_temp','job_temp','dataset_temp','site_temp'] movement_options = ['input','output','both'] def __init__(self,*args,**kwargs): self['type'] = 'permanent' self['movement'] = 'both' super(Data,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'compression': ret[n] = [self[n],self.compression_options] elif n == 'type': ret[n] = [self[n],self.type_options] elif n == 'movement': ret[n] = [self[n],self.movement_options] else: ret[n] = self[n] return ret
[docs] def convert(self): super(Data,self).convert()
[docs] def valid(self): try: return ( super(Data,self).valid() and self['type'] in self.type_options and self['movement'] in self.movement_options ) except Exception: return False
[docs] def storage_location(self,env): """ Get storage location from the environment. :param env: environment :returns: storage location as a string, or raises Exception """ type = self['type'].lower() if type not in Data.type_options: raise Exception('Data.type is undefined') if 'options' in env and type in env['options']: return env['options'][type] elif type == 'permanent': if 'options' in env and 'data_url' in env['options']: return env['options']['data_url'] else: raise Exception('data_url not defined in env[\'options\']') else: raise Exception('%s not defined in env' % type)
[docs] def filecatalog(self,env): """ Get filecatalog from the environment. :param env: environment :returns: FileCatalog object, or raises Exception """ type = self['type'].lower() if type not in Data.type_options: raise Exception('Data.type is undefined') elif type in ('job_temp','dataset_temp','site_temp'): if 'options' in env and 'filecatalog_temp' in env['options']: return env['options']['filecatalog_temp'] elif type == 'permanent': if 'options' in env and 'filecatalog' in env['options']: return env['options']['filecatalog'] raise Exception('%s not defined in env' % type)
[docs] class DifPlus(dict): """ A DifPlus object. :ivar dif: None :ivar plus: None """ plural = 'DifPlus' def __init__(self,*args,**kwargs): self['dif'] = None self['plus'] = None super(DifPlus,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'dif': ret[n] = [self[n],'Dif'] elif n == 'plus': ret[n] = [self[n],'Plus'] else: ret[n] = self[n] return ret
[docs] def convert(self): if self['dif'] and not isinstance(self['dif'],Dif): tmp = Dif(self['dif']) tmp.convert() self['dif'] = tmp if self['plus'] and not isinstance(Plus): tmp = Plus(self['plus']) tmp.convert() self['plus'] = tmp
[docs] def valid(self): try: return ( (self['dif'] is None or (isinstance(self['dif'],Dif) and self['dif'].valid())) and (self['plus'] is None or (isinstance(self['plus'],Plus) and self['plus'].valid())) ) except Exception: return False
[docs] class Dif(dict): """ A Dif object. :ivar entry_id: None :ivar entry_title: None :ivar parameters: ' ' :ivar iso_topic_category: 'geoscientificinformation' :ivar data_ceter: None :ivar summary: ' ' :ivar metadata_name: '[CEOS IDN DIF]' :ivar metadata_version: '9.4' :ivar personnel: [] :ivar sensor_name: 'ICECUBE' :ivar source_name: 'SIMULATION' :ivar dif_creation_date: time.strftime("%Y-%m-%d") """ plural = 'Dif' # TODO: move these to the DB, or somewhere IceCube-specific valid_parameters = [ "SPACE SCIENCE > Astrophysics > Neutrinos", "SPACE SCIENCE > Astrophysics > Neutrinos > Atmospheric", "SPACE SCIENCE > Astrophysics > Neutrinos > Extraterrestrial Point Source", "SPACE SCIENCE > Astrophysics > Neutrinos > Gamma Ray Burst", "SPACE SCIENCE > Astrophysics > Neutrinos > WIMPS", "SPACE SCIENCE > Astrophysics > Neutrinos > Diffuse Source", "SPACE SCIENCE > Astrophysics > Neutrinos > Extreme High Energy", "SPACE SCIENCE > Astrophysics > Neutrinos > Super Nova", "SPACE SCIENCE > Astrophysics > Neutrinos > Cosmic Ray Muon Component", "SPACE SCIENCE > Astrophysics > Neutrinos > Tau", "SPACE SCIENCE > Astrophysics > Neutrinos > Cascades", "SPACE SCIENCE > Astrophysics > Neutrinos > Galactic Plane", "SPACE SCIENCE > Astrophysics > Cosmic Rays", "SPACE SCIENCE > Astrophysics > Cosmic Rays > Composition", "SPACE SCIENCE > Astrophysics > Cosmic Rays > Air Shower", "SPACE SCIENCE > Astrophysics > Cosmic Rays > Cosmic Ray Muons", "SPACE SCIENCE > Astrophysics > Cosmic Rays > Moon Shadow", "SPACE SCIENCE > Engineering > Sensor Characteristics", "SPACE SCIENCE > Engineering > Sensor Characteristics > Photomultiplier Tubes", "SPACE SCIENCE > Engineering > Sensor Characteristics > Digital Optical Modules", "EARTH SCIENCE > Cryosphere > Glaciers/Ice Sheets", "EARTH SCIENCE > Cryosphere > Glaciers/Ice Sheets > Hot Water Drilling", "EARTH SCIENCE > Cryosphere > Glaciers/Ice Sheets > Hot Water Drilling > Hole Drilling", "EARTH SCIENCE > Cryosphere > Glaciers/Ice Sheets > Hot Water Drilling > Hole Refreeze" ] valid_source_name = { "SIMULATION":"Data which are numerically generated", "EXPERIMENTAL":"Data with an instrumentation based source" } valid_sensor_name = { "AMANDA-A":"Prototype Antarctic Muon and Neutrino Detector Array", "AMANDA":"Antarctic Muon and Neutrino Detector Array", "SPASE-1":"South Pole Air Shower Experiment 1", "SPASE-2":"South Pole Air Shower Experiment 2", "VULCAN":"South Pole Air-Cherenkov Telescope", "RICE":"Radio Ice Cherenkov Experiment", "GASP":"Gamma Astronomy-South Pole", "ICECUBE":"IceCube", "ICETOP":"IceTop", "EHWD":"Enhanced Hot Water Drill", "SPTR":"South Pole TDRSS Relay", "RPSC-MET":"Raytheon Polar Services Corporation Meteorology" } def __init__(self,*args,**kwargs): self['entry_id'] = None self['entry_title'] = None self['parameters'] = '' self['iso_topic_category'] = 'geoscientificinformation' self['data_ceter'] = None self['summary'] = '' self['metadata_name'] = '[CEOS IDN DIF]' self['metadata_version'] = '9.4' self['personnel'] = [] self['sensor_name'] = 'ICECUBE' self['source_name'] = 'SIMULATION' self['dif_creation_date'] = time.strftime("%Y-%m-%d") super(Dif,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'personnel': ret[n] = [self[n],'Personnel'] else: ret[n] = self[n] return ret
[docs] def convert(self): for i,p in enumerate(self['personnel']): if not isinstance(p,Personnel): tmp = Personnel(p) tmp.convert() self['personnel'][i] = tmp
[docs] def valid(self): try: return ( (self['entry_id'] is None or isinstance(self['entry_id'],(Number,String))) and (self['entry_title'] is None or isinstance(self['entry_title'],String)) and isinstance(self['parameters'],String) and isinstance(self['iso_topic_category'],String) and (self['data_ceter'] is None or ( isinstance(self['data_ceter'],DataCenter) and self['data_center'].valid()) ) and isinstance(self['summary'],String) and isinstance(self['metadata_name'],String) and isinstance(self['metadata_version'],(Number,String)) and all(isinstance(p,Personnel) and p.valid() for p in self['personnel']) and isinstance(self['sensor_name'],String) and isinstance(self['source_name'],String) and isinstance(self['dif_creation_date'],(Number,String)) ) except Exception: return False
[docs] class Plus(dict): """ A Plus object. :ivar start: None :ivar end: None :ivar category: None :ivar subcategory: None :ivar run_number: None :ivar i3db_key: None :ivar simdb_key: None :ivar project: [] -- [{name: version}] :ivar steering_file: None :ivar log_file: None :ivar command_line: None """ plural = 'Plus' valid_category = [ "unclassified", "generated", "propagated", "unbiased", "filtered", "calibration", "monitoring", "webcam", "hole", "TestDAQ", "FAT", "log", "upmu", "minbias", "cascades", "high-energy", "wimp", "GRB" ] def __init__(self,*args,**kwargs): self['start'] = None self['end'] = None self['category'] = None self['subcategory'] = None self['run_number'] = None self['i3db_key'] = None self['simdb_key'] = None self['project'] = [] self['steering_file'] = None self['log_file'] = None self['command_line'] = None super(Plus,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'project': ret[n] = [self[n],{}] else: ret[n] = self[n] return ret
[docs] def convert(self): pass
[docs] def valid(self): try: return ( (self['start'] is None or isinstance(self['start'],(Number,String))) and (self['end'] is None or isinstance(self['end'],(Number,String))) and (self['category'] is None or isinstance(self['category'],String)) and (self['subcategory'] is None or isinstance(self['subcategory'],String)) and (self['run_number'] is None or isinstance(self['run_number'],(Number,String))) and (self['i3db_key'] is None or isinstance(self['i3db_key'],(Number,String))) and (self['simdb_key'] is None or isinstance(self['simdb_key'],(Number,String))) and all(( isinstance(p,dict) and all(isinstance(k,String) for k in p.keys()) and all(isinstance(v,(Number,String)) for v in p.values()) ) for p in self['project']) and (self['steering_file'] is None or isinstance(self['steering_file'],String)) and (self['log_file'] is None or isinstance(self['log_file'],String)) and (self['command_line'] is None or isinstance(self['command_line'],String)) ) except Exception: return False
[docs] class Personnel(dict): """ A Personnel object. :ivar role: None :ivar first_name: None :ivar last_name: None :ivar email: None """ plural = 'Personnel' def __init__(self,*args,**kwargs): self['role'] = None self['first_name'] = None self['last_name'] = None self['email'] = None super(Personnel,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: ret[n] = self[n] return ret
[docs] def convert(self): pass
[docs] def valid(self): try: return ( (self['role'] is None or isinstance(self['role'],String)) and (self['first_name'] is None or isinstance(self['first_name'],String)) and (self['last_name'] is None or isinstance(self['last_name'],String)) and (self['email'] is None or isinstance(self['email'],String)) ) except Exception: return False
[docs] class DataCenter(dict): """ A Data Center object. :ivar name: None :ivar personnel: [] """ plural = 'DataCenter' valid_names = ['UWI-MAD/A3RI > Antarctic Astronomy and Astrophysics Research Institute, University of Wisconsin, Madison'] def __init__(self,*args,**kwargs): self['name'] = None self['personnel'] = [] super(DataCenter,self).__init__(*args,**kwargs)
[docs] def output(self): """Output dict with values and (optionally) the object name for new objects.""" ret = {} for n in self: if n == 'personnel': ret[n] = [self[n],'Personnel'] else: ret[n] = self[n] return ret
[docs] def convert(self): for i,p in enumerate(self['personnel']): if not isinstance(p,Personnel): tmp = Personnel(p) tmp.convert() self['personnel'][i] = tmp
[docs] def valid(self): try: return ( (self['name'] is None or isinstance(self['name'],String)) and all(isinstance(p,Personnel) and p.valid() for p in self['personnel']) ) except Exception: return False