ATLAS Offline Software
Loading...
Searching...
No Matches
JobProperties.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3#=======================================================================
4# File: JobProperties/python/JobProperties.py
5#=======================================================================
6""" JobProperties.
7
8 prototype for a unified ATLAS job properties definition.
9
10 Here we will add more inforamtion about the usage............
11 .............................................................
12 .............................................................
13 .............................................................
14
15"""
16
17jobPropertiesDisallowed = False
18
19import functools
20
21#
22#
23__author__= 'M. Gallas, P. Calafiura, S. Binet'
24__version__= '$Revision: 1.18 $'
25__doc__= "JobProperties"
26# data
27__all__ = [ "JobProperties"]
28#=======================================================================
29# imports
30#=======================================================================
31import re, os, pickle, pprint
32from AthenaCommon import Logging
33
34#=======================================================================
35def _isCompatible( allowedTypes, value ):
36 # this function is similar to PropertyProxy._isCompatible, but with
37 # some twists to handle the peculiarity of JobProperty's implementation
38
39 offcount = 0
40 for a in allowedTypes:
41 try:
42 tp = eval( a )
43 except Exception:
44 if type(value).__name__ in allowedTypes:
45 return True # old style, for e.g. function
46 offcount += 1
47 continue
48
49 if ( tp == str and len(allowedTypes) == 1 ) and not isinstance( value, tp ):
50 # special case, insist on exact match for str (no conversions allowed)
51 return False
52 elif type(value) is str and not isinstance( value, tp ):
53 # similarly, insist on exact match for str (no conversions allowed)
54 pass # offcount will cause a failure, unless another type matches
55 elif tp == int and type(value) is float:
56 # special case, insist on strict match for integer types
57 pass # id. as for strings above
58 elif ( tp == bool ) and not (type(value) in [bool, int]):
59 # restrictions on bool, as the code below does "== False", so even though
60 # a lot of types convert to bool, only bool and int (and float) behave as
61 # expected on comparison
62 pass # id. as for strings above
63 else:
64 # all other types: accept if conversion allowed
65 try:
66 tp( value ) # conversion needed to check allowedValues
67 return True
68 except Exception:
69 pass
70
71 # accept if no types, or if there are uncheckable types left
72 return not (len(allowedTypes) - offcount)
73
74#=======================================================================
75# classes
76#=======================================================================
78 def __new__( self, name, bases, dct ):
79 # StoredValue type check
80 try:
81 sv = dct[ 'StoredValue' ]
82 if sv is not None and not _isCompatible( dct[ 'allowedTypes' ], sv ):
83 raise TypeError(
84 'type of StoredValue (%s) not in allowedTypes (%s)' %
85 (type(sv).__name__,dct[ 'allowedTypes' ])
86 )
87 except KeyError:
88 pass
89
90 # StoredValue value check
91 try:
92 sv = dct[ 'StoredValue' ]
93 if sv is not None and dct[ 'allowedValues' ] and sv not in dct[ 'allowedValues' ]:
94 raise TypeError(
95 'value of StoredValue (%s) not in allowedValues (%s)' %
96 (str(sv),dct[ 'allowedValues' ])
97 )
98 except KeyError:
99 pass
100
101 return type.__new__( self, name, bases, dct )
102
103
104@functools.total_ordering
105class JobProperty(metaclass = _JobPropertyMeta):
106 """ Base class for the job properties.
107
108 The job properties are class definitions that will be
109 instanciated at the time the job property is added to global
110 container for the job properties called "jobproperties".
111 The job properties can be also added to sub-containers within
112 the "jobproperties" container.
113
114
115 All the job properties must be defined as subclasses of
116 "JobProperty" and, as derived classes, can re-define:
117
118 statusOn, allowedTypes and allowedValues and StoredValue
119
120 The setting of the StoredValue will automatically check the new
121 value against the lists allowedTypes and allowedValues. A given
122 StoredValue can not be changed if the corresponding job property
123 is locked.
124
125 The actual Value of the JobProperty is (statusOn AND StoredValue)
126
127 """
128
129 statusOn=False
130 allowedTypes=list()
131 allowedValues=list()
132 StoredValue=None
133 _log=Logging.logging.getLogger('JobProperty ::')
134 _nInstancesContextDict=dict()
135 _locked=False
136
137 def __init__(self,context=''):
138 """ Each JobProperty has only one possible instance in a given
139 context. The context is given by the container and sub-containers
140 to which the job property belongs.
141 """
142 if jobPropertiesDisallowed:
143 raise RuntimeError("JobProperty should not be called in pure CA config")
144
145 context_name=context+'.'+self.__class__.__name__
146 if not (context_name in self.__class__._nInstancesContextDict.keys()):
147 self.__class__._nInstancesContextDict[context_name]=self
148 self.__name__=self.__class__.__name__
149 self._context_name=context+'.'+self.__class__.__name__
150 else:
151 self._log.error("There is already an instance of %s at %s ",
152 self.__class__.__name__, context_name)
153 raise RuntimeError('JobProperties: JobProperty:: __init__()')
154
155 def __bool__(self):
156 return self.get_Value()
157
158 def __eq__(self, rhs):
159 if isinstance(rhs, JobProperty):
160 # FIXME: should we only allow comparison between same class
161 # rather than b/w JobProperties ?
162 # OTOH, JobProperty-derived classes are 'singleton'...
163 return self() == rhs()
164 return self() == rhs
165
166 def __lt__(self, rhs):
167 if isinstance(rhs, JobProperty):
168 # FIXME: should we only allow comparison between same class
169 # rather than b/w JobProperties ?
170 # OTOH, JobProperty-derived classes are 'singleton'...
171 return self() < rhs()
172 return self() < rhs
173
174 def __call__(self):
175 return self.get_Value()
176
177 def __str__(self):
178 return self.print_JobProperty('print_v')
179
180 def __iadd__(self,value):
181 aux=self.get_Value()
182 aux+=value
183 self.StoredValue = aux
184 return self.StoredValue
185
186
187 def is_locked(self):
188 return self._locked
189
190 def _do_action(self):
191 """ A place-holder for actions to be taken at the time
192 the JobProperty.StoredValue is set or JobProperty.statusOn
193 is set to True.
194
195 (for advanced use)
196 """
197 pass
198
199 def _undo_action(self):
200 """ A place-holder for actions to be taken at the time
201 the JobProperty.statusOn is set to False.
202
203 (for advanced use)
204 """
205 pass
206
207 def set_On(self):
208 """ Sets statusOn equals to True.
209 """
210 if not(self._locked):
211 self.__dict__['statusOn']=True
212 self._do_action()
213 else:
214 self._log.info('The JobProperty %s is blocked', self.__name__)
215
216 def set_Off(self):
217 """ Sets statusOn equals to False.
218 """
219 if not(self._locked):
220 self.__dict__['statusOn']=False
221 self._undo_action()
222 else:
223 self._log.info('The JobProperty %s is blocked', self.__name__)
224
225 def lock(self):
226 """ lock the property
227 """
228 self._locked=True
229
230 def unlock(self):
231 """ unlock the property
232 """
233 self._locked=False
234 self._log.warning('The property %s is being unlocked ',
235 self._context_name)
236
237
238# def __getattribute__(self, name):
239# obj_p=object.__getattribute__(self, name)
240# if name=='StoredValue':
241# self._log.error('You must access the value of the jobproperty'+
242# ' using the get_Value() method. ')
243# return obj_p
244
245 def __setattr__(self, name, n_value):
246 if hasattr(self, name):
247 if name=='StoredValue' and not(self._locked):
248 if len(self.allowedValues) == 0 or \
249 True in [ x == n_value for x in self.allowedValues ]:
250 # WLAV: the following is rather puzzling in the difference
251 # of treatment of bools, especially since it does not work
252 # as expected, and even worse for compatible types. It is
253 # left as-is in place, since changing it has side-effects on
254 # RecExCommon/myTopOptions.py ...
255 if len(self.allowedTypes) == 0:
256 self.__dict__[name] = n_value
257 self.set_On()
258 elif _isCompatible(self.allowedTypes, n_value):
259 self.__dict__[name] = n_value
260 if isinstance(n_value, bool) and n_value is False:
261 self.set_Off()
262 else:
263 self.set_On()
264 else:
265 raise ValueError(
266 ' %s is not the expected type for: %s' %
267 (n_value, self._context_name)
268 )
269 else:
270 raise ValueError(
271 ' %s is not the expected type and/or the value is not allowed for: %s' %
272 (n_value, self._context_name)
273 )
274 elif name == 'StoredValue' and self._locked:
275 self._log.info('The JobProperty %s is blocked', self.__name__)
276 else:
277 self.__dict__[name] = n_value
278 elif name == '__name__' or name == '_context_name':
279 self.__dict__[name] = n_value
280 else:
281 raise AttributeError("JobProperty:: You cannot add attributes to %s" % self)
282
283 def set_Value(self, n_value):
284 """ Sets the value of the JobProperty .
285
286 MyJobProperty.set_Value(NewValue)
287
288 is equivalent to
289
290 MyJobProperty=NewValue
291
292 It is checked the type and if the value is allowed. The
293 statusOn is set to True automatically.
294 This method is here for backwards compatibility.
295 """
296#Joerg S/Martin W advice
297 self.StoredValue=n_value
298
299 def get_Value(self):
300 """ Gets the value of the job property.
301
302 This is the recommended way top retrieve the actual
303 value of the job property. For boolean properties it
304 gives the and(statusOn,StoredValue). For the rest of the
305 properties it gives the StoredValue if the statusOn==True
306 otherwise it gives None.
307 """
308 obj_p=object.__getattribute__(self, 'StoredValue')
309 if isinstance(obj_p, type(True)):
310 return obj_p & self.statusOn
311 else:
312 if self.statusOn:
313 return obj_p
314 else:
315 self._log.warning('You are attempting to access the job'+
316 'property %s which has not been set', self._context_name)
317 return None
318
319 def set_Value_and_Lock(self,n_value):
320 """ Sets the value of the JobProperty and lock it in one command .
321 """
322 self.set_Value(n_value)
323 self.lock()
324
325 def isDefault (self):
326 """check whether a flag has been modified or if it is still containing
327 its default value.
328 """
329 val = self.__getattribute__('StoredValue')
330 dft = self.__class__.StoredValue
331 return val==dft
332
333
334
335 def help(self):
336 """ Prints the documentation available for the JobProperty.
337 together with the actual value, values allowed and types
338 allowed.
339 """
340 self._log.info('### Help for the class %s ###',
342 self._log.info(self.__doc__)
343
344 print ('## job property:',self._context_name, self.statusOn, self.StoredValue)
345 print ('## allowed Values:',self.allowedValues)
346 print ('## default Value:', self.__class__.StoredValue )
347 print ('## allowed Types :',self.allowedTypes )
348 self._log.info('### End of the help for the class %s ###',
349 self.__class__)
350
351 def toBePrinted (self):
352 """ compute a string which is : empty if flag is set to default value
353 (<DefaultValue> if flag not set to default value or flas is off
354 """
355 if self.statusOn:
356 derived = self.get_Value() # can be overwritten
357 else:
358 derived = None
359 stored = self.__getattribute__('StoredValue')
360 default = self.__class__.StoredValue
361 if derived==stored:
362 tbp = '%s' % pprint.pformat(stored)
363 else:
364 tbp= '%s (Stored: %s)' %(pprint.pformat(derived),pprint.pformat(stored))
365 if stored!=default:
366 tbp= '%s (Default: %s)' %(tbp,pprint.pformat(default))
367
368 if not self.statusOn:
369 tbp = 'Off : %s ' % tbp
370
371 return tbp
372
373
374 def print_JobProperty(self,mode='minimal'):
375 """ Prints the information of the JobProperty
376
377 The available options are: 'minimal','full','tree','tree&value','tree&valuenondefault'
378 """
379 indent=''
380 obj_p=object.__getattribute__(self, 'StoredValue')
381 if self.statusOn:
382 obj_ps=obj_p
383 else:
384 obj_ps=None
385 for i in range(self._context_name.count('.')-2):
386 indent+='-'
387 if self.is_locked():
388 indent+='x'
389 else:
390 indent+='-'
391
392 if mode=='minimal':
393 self._log.info(" %s-> %s = %s ",indent,
394 self._context_name,pprint.pformat(obj_ps) )
395
396 elif(mode=='full'):
397 if len(self.allowedTypes)>0:
398 at=self.allowedTypes
399 else:
400 at='- - -'
401 if len(self.allowedValues)>0:
402 av=pprint.pformat(self.allowedValues)
403 else:
404 av='- - -'
405 self._log.info("%s-> %s = %s\n %40s %s\n %40s \
406 %s\n %40s %s\n %40s %s\n %40s %s\n %40s %s",
407 indent,
408 self._context_name,
409 self.__getattribute__('StoredValue'),
410 'allowedTypes :',at,
411 'allowedValues :',av,
412 'default value :', self.__class__.StoredValue,
413 'statusOn :',self.statusOn,
414 'locked :',self.is_locked(),
415 'StoredValue :',pprint.pformat(obj_p))
416 elif(mode=='tree'):
417 print (' |'+indent+' '+self.__name__)
418 elif(mode.startswith('tree&value')):
419 if mode=='tree&value':
420 printit=True
421 elif mode=='tree&valuenondefault':
422 if self.isDefault():
423 printit=False
424 else:
425 printit=True
426 else:
427 raise RuntimeError("This is a non valid print mode %s " % (mode,))
428 if printit:
429 print (' |'+indent+' '+self.__name__+" = "+\
430 self.toBePrinted())
431# fnToBePrinted(self)
432
433 elif(mode=='print_v'):
434 return ' |'+indent+' '+self.__name__+" = "+\
435 self.toBePrinted()
436 # fnToBePrinted(self)
437
438 else:
439 raise ValueError('Unknow mode, possible modes are: '
440 'minimal, full, tree, tree&value ')
441
442
443
445 """ Container for the JobProperties.
446
447 By definition it will contain a minimal set of flags,
448 but this set can be increased during the job configuration
449 using the "import_JobProperties" or "add_JobProperty"
450 methods. In this way it can be adapted to the diferent
451 job needs.
452 A JobPropertyContainer can contain other JobProperty
453 containers, that can be added using the "add_Container"
454 method.
455 There is a top global job properties container instance
456 which is called "jobproperties" that has to be used as starting
457 point.
458
459 """
460 _log=Logging.logging.getLogger('JobPropertyContainer::')
461 _nInstancesContextList=list()
462 _locked=False
463
464 def __init__(self,context=''):
465 """ Each JobPropertyContainer has only one possible instance
466 in a given context.
467 """
468 if context=='':
469 context_name=self.__class__.__name__
470 else:
471 context_name=context+'.'+self.__class__.__name__
472 if not (context_name in self.__class__._nInstancesContextList):
473 self.__class__._nInstancesContextList.append(context_name)
474 self.__name__=self.__class__.__name__
475 self._context_name=context_name
476 else:
477 self._log.error('There is already an instance of %s at %s',
478 self.__class__.__name__, context_name)
479 raise RuntimeError('JobProperties:JobPropertyContainer: __init__()')
480
481 def __setattr__(self, name, n_value):
482 # Protection for the already defined JobProperties classes
483 # and inmediate asignation of a new StoredValue
484 if not(name=='__name__' or name=='_context_name' or name=='_locked'):
485 if (issubclass(n_value.__class__,JobProperty) or
486 issubclass(n_value.__class__,JobPropertyContainer)):
487 pass
488 elif(self.__dict__.__contains__(name)):
489 pass
490 else:
491 errString="JobPropertyContainer:: %s does not have property %s" % (self._context_name, name)
492 try:
493 from difflib import get_close_matches
494 closestMatch=get_close_matches(name,self.__dict__.keys(),1)
495 if len(closestMatch)>0:
496 errString+=". Did you mean \'%s\'?" % closestMatch[0]
497 except Exception:
498 pass #No execption from here
499
500 raise AttributeError(errString)
501 try:
502 protected=hasattr(self.__dict__[name],'_context_name')
503 except Exception:
504 protected=False
505 if not protected:
506 self.__dict__[name] = n_value
507 else:
508 property_obj=self.__dict__.get(name)
509 property_obj.StoredValue=n_value
510 property_obj.statusOn=True
511
512
513
514 def __str__(self):
515 if self._context_name.count('.')==0:
516 # the top container case
517 print_view=' [-]'+self.__name__+'\n'+' | '+'\n'
518 for k in sorted(self.__dict__.keys()):
519 m=self.__dict__.get(k)
520 if hasattr(m,'print_JobProperty'):
521 m.print_JobProperty('print_v')
522 print_view+=str(m)+'\n'
523 elif hasattr(m,'print_JobProperties'):
524 indent='-'
525 for i in range(m._context_name.count('.')-1):
526 indent+='-'
527 print_view+=' /'+indent+'> ## '+m.__name__+' ## '+'\n'
528 print_view+=m.print_JobProperties('print_v')
529 return print_view
530 else:
531 return self.print_JobProperties('print_v')
532
533 def is_locked(self):
534 return self._locked
535
536 def help(self):
537 """ Prints the documentation generated with the JobProperty
538 container.
539 """
540 self._log.info('### Help for the class %s ###',
542 self._log.info(self.__doc__)
543 self._log.info('### End of the help for the class %s ###',
544 self.__class__)
545
546 def import_JobProperties(self,module_name):
547 """ Import modules with JobProperties specific to a given job
548 configuration.
549
550 The new specific set of JobProperties added must have a name
551 without '_' and subclass the base class "JobProperty".
552 """
553 try:
554 if(module_name.count('.')==0):
555 module=__import__(module_name,globals(),locals())
556 elif(module_name.count('.')>0):
557 module=__import__(module_name,globals(),locals(),\
558 ['JobProperties'])
559 except ImportError:
560 import traceback
561 traceback.print_exc()
562 self._log.error(" import_JobProperties: No module named %s",
563 module_name)
564 return None
565 mo=vars(module)
566 p = re.compile('_') # mgallas --> look into this and relax it
567 for i in mo.keys():
568 if(not(p.match(i)) and
569 (i !='JobPropertyContainer' and i!='JobProperty' and
570 i !='jobproperties')):
571 mok=mo.get(i)
572 setattr(self,mok.__name__,mok(self._context_name))
573
574 def import_Flags(self,module_name):
575 """ OBSOLETE: Use import_JobProperties
576
577 Import modules with JobProperties specific to a given job
578 configuration.
579
580 The new specific set of JobProperties added must have a name
581 without '_' and subclass the base class "JobProperty".
582
583 IMPORTANT: "import_Flags" method is calling the new method
584 "import_JobProperties". For some time import_Flags
585 it will work but it will be removed soon
586 """
587 self._log.warning('OBSOLETE method: use import_JobProperties')
588 self.import_JobProperties(module_name)
589
590 def add_Container(self,new_container):
591 """ Adds a container of JobProperties of the type
592 JobPropertyContainer to the existing container.
593 """
594 if issubclass(new_container,JobPropertyContainer):
595 issubclass(new_container,JobPropertyContainer)
596 if not(new_container.__name__ in self.__dict__.keys()):
597 setattr(self,new_container.__name__,
598 new_container(self._context_name))
599 else:
600 self._log.warning('The container %s is already in %s',
601 new_container.__name__,self.__name__)
602 else:
603 self._log.error('You are not adding a JobPropertyContainer ')
604
605 def add_JobProperty(self, new_flag):
606 """ Add one JobProperty to the present container.
607
608 The new JobProperty added must have a name
609 without '_' and subclass the base class "JobProperty".
610 """
611 if issubclass(new_flag,JobProperty):
612 if not(new_flag.__name__ in self.__dict__.keys()):
613 setattr(self,new_flag.__name__,new_flag(self._context_name))
614 else:
615 self._log.warning('The flag %s is already in %s',
616 new_flag.__name__, self.__name__)
617 else:
618 self._log.error('You are not adding a JobProperty ')
619
620 def del_JobProperty(self, del_flag):
621 """ Deletes one JobProperty from the present container.
622 """
623 if (issubclass(del_flag,JobProperty) and
624 hasattr(self,del_flag.__name__)):
625 flag_obj=getattr(self,del_flag.__name__)
626 delattr(self,del_flag.__name__)
627 del_flag._nInstancesContextDict.pop(flag_obj._context_name)
628 self._log.debug('The JobProperty %s has been deleted',
629 del_flag.__name__)
630 else:
631 self._log.info('The JobProperty %s is not defined here',
632 del_flag.__name__)
633
634 def del_Container(self, del_container):
635 """ Deletes one sub-container of the present container.
636 """
637 if (issubclass(del_container,JobPropertyContainer) and
638 hasattr(self,del_container.__name__)):
639 flagcontainer_obj=getattr(self,del_container.__name__)
640 delattr(self,del_container.__name__)
641 del_container._nInstancesContextList.remove(flagcontainer_obj._context_name)
642 self._log.warning('The JobProperty Container %s has been deleted',
643 del_container.__name__)
644 else:
645 self._log.info('The JobProperty Container %s is not defined here',
646 del_container.__name__)
648 """ Locks the Values of the JobProperties
649 """
650 for j in self.__dict__.keys():
651 j_obj=self.__dict__.get(j)
652 if hasattr(j_obj,'lock_JobProperties'):
653 j_obj.lock_JobProperties()
654 j_obj._locked=True
655 elif hasattr(j_obj,'_locked'):
656 j_obj._locked=True
657 self._log.info('The JobProperty Container %s is locked',
658 self.__name__)
659
661 """ Unlocks the Values of the JobProperties
662 """
663 for j in self.__dict__.keys():
664 j_obj=self.__dict__.get(j)
665 if hasattr(j_obj,'lock_JobProperties'):
666 j_obj.unlock_JobProperties()
667 j_obj._locked=False
668 elif hasattr(j_obj,'_locked'):
669 j_obj._locked=False
670 self._log.warning('The JobProperty Container %s is being unlocked ',
671 self.__name__)
672
673 def print_JobProperties(self,mode='minimal'):
674 """Prints all the JobProperties in the container.
675
676 It will print also the JobProperties within the sub-containers
677 present in the container.
678
679 The available options are: 'minimal','full','tree','tree&value','tree&valuenondefault'
680 """
681 print_view=''
682 if self._context_name.count('.')==0:
683 additionalinfo=''
684 if (mode=='tree&valuenondefault'):
685 additionalinfo="(Only non default values)"
686 if mode != "minimal":
687 additionalinfo+="(X indicates locked properties)"
688
689 self._log.info("### Printing the job properties container %s %s ###",
690 self.__name__ ,additionalinfo)
691
692 if(mode=='tree' or mode.startswith('tree&value')):
693 print (' [-]'+self.__name__)
694 print (' | ')
695 elif(mode=='print_v'):
696 print_view+=' [-]'+self.__name__+'\n'+' | '+'\n'
697 else:
698 self._log.info(' [-]'+self.__name__)
699
700 for k in sorted(self.__dict__.keys()):
701 m=self.__dict__.get(k)
702 if hasattr(m,'print_JobProperty'):
703 m.print_JobProperty(mode)
704 if mode=='print_v':
705 print_view+=str(m)+'\n'
706 elif hasattr(m,'print_JobProperties'):
707 indent='-'
708 for i in range(m._context_name.count('.')-1):
709 indent+='-'
710 if(mode=='tree' or mode.startswith('tree&value')):
711 print (' /'+indent+'> ## '+m.__name__+' ## ')
712 elif(mode=='print_v'):
713 print_view+=' /'+indent+'> ## '+m.__name__+' ## '+'\n'
714 else:
715 self._log.info(' /'+indent+'> ## '+m.__name__+' ## ')
716
717 if(mode=='print_v'):
718 print_view+=m.print_JobProperties(mode)
719 else:
720 m.print_JobProperties(mode)
721
722 if mode=='print_v':
723 return print_view
724 if self._context_name.count('.')==0:
725 self._log.info("### Ends the job properties container %s ###",
726 self.__name__ )
727
728 def set_JobProperties(self,data):
729 """ It can be used to set several job properties in different
730 JobContainers in one step.
731
732
733 The expected data must be a dict as for example:
734
735 data={'JobProperties.SimFlags':{'init_Level':2,'SeedsG4':.98},
736 'JobProperties.Digitization':{'writeMuonDigit':False}
737 }
738
739 """
740 tp=type(data)
741 if tp.__name__=='dict':
742 list_context=list(JobProperty._nInstancesContextDict.keys())
743 for i in data.keys():
744 for j in data[i].keys():
745 if list_context.count(i+'.'+j)==1:
746 jp=JobProperty._nInstancesContextDict[i+'.'+j]
747 jp.set_Value(data[i][j])
748 self._log.info("The JobProperty %s has been set to %s",
749 i+'.'+j,data[i][j])
750 else:
751 self._log.warning("The JobProperty %s does not exist",
752 i+'.'+j)
753 else:
754 raise ValueError('The received data is has not the expected'
755 'type/format')
756
757 def __getattribute__(self,name):
758 try:
759 return object.__getattribute__(self, name)
760 except AttributeError:
761
762 errString="JobPropertyContainer:: %s does not have property %s" % (object.__getattribute__(self,'_context_name'), name)
763 allattrs=object.__getattribute__(self,'__dict__').keys()
764 from difflib import get_close_matches
765 closestMatch=get_close_matches(name,allattrs,1)
766 if len(closestMatch)>0:
767 errString+=". Did you mean \'%s\'?" % closestMatch[0]
768 raise AttributeError(errString)
769 pass
770
771
772#=======================================================================
773# data
774#=======================================================================
776 """ The global job properties container.
777
778 - This will be the unique container with 'global' context
779 and the rest of the containers or general job properties
780 will be added to this container.
781
782 - The job properties/containers added to this container do not
783 need to be instances. The instance is created and associated to
784 context at the time the job properties/container is added.
785 User needs only to define the job properties/container he/she
786 want to add.
787 """
788jobproperties=JobProperties()
789
790#=======================================================================
791# functions
792#=======================================================================
793def save_jobproperties(file_name):
794 """ Saves the "jobproperties" container of JobProperties.
795 """
796 try:
797 if not (file_name.__contains__(os.sep)) :
798 file_name=os.getcwd()+os.sep+file_name
799 f=open(file_name,'w')
800# data=[JobPropertyContainer,JobProperty,jobproperties]
801# pickle.dump(data,f)
802 pickle.dump(jobproperties,f)
803 f.close()
804 except IOError:
805 print ('It is not possible to save the jobproperties ')
806def load_jobproperties(file_name):
807 """ Loads the "jobproperties" container of JobProperties.
808 """
809 try:
810 if not (file_name.__contains__(os.sep)) :
811 file_name=os.getcwd()+os.sep+file_name
812 f=open(file_name,'r')
813 return pickle.load(f)
814 except IOError:
815 print ('It is not possible to load the jobproperties ')
816
if(febId1==febId2)
const bool debug
__setattr__(self, name, n_value)
print_JobProperty(self, mode='minimal')
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
load_jobproperties(file_name)
_isCompatible(allowedTypes, value)
save_jobproperties(file_name)