8 prototype for a unified ATLAS job properties definition.
10 Here we will add more inforamtion about the usage............
11 .............................................................
12 .............................................................
13 .............................................................
17 jobPropertiesDisallowed =
False
23 __author__=
'M. Gallas, P. Calafiura, S. Binet'
24 __version__=
'$Revision: 1.18 $'
25 __doc__=
"JobProperties"
27 __all__ = [
"JobProperties"]
31 import re, os, pickle, pprint
32 from AthenaCommon
import Logging
40 for a
in allowedTypes:
44 if type(value).__name__
in allowedTypes:
49 if ( tp == str
and len(allowedTypes) == 1 )
and not isinstance( value, tp ):
52 elif type(value)
is str
and not isinstance( value, tp ):
55 elif tp == int
and type(value)
is float:
58 elif ( tp == bool )
and not (
type(value)
in [bool, int]):
72 return not (len(allowedTypes) - offcount)
81 sv = dct[
'StoredValue' ]
82 if sv
is not None and not _isCompatible( dct[
'allowedTypes' ], sv ):
84 'type of StoredValue (%s) not in allowedTypes (%s)' %
85 (
type(sv).__name__,dct[
'allowedTypes' ])
92 sv = dct[
'StoredValue' ]
93 if sv
is not None and dct[
'allowedValues' ]
and sv
not in dct[
'allowedValues' ]:
95 'value of StoredValue (%s) not in allowedValues (%s)' %
96 (
str(sv),dct[
'allowedValues' ])
101 return type.__new__( self, name, bases, dct )
104 @functools.total_ordering
106 """ Base class for the job properties.
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.
115 All the job properties must be defined as subclasses of
116 "JobProperty" and, as derived classes, can re-define:
118 statusOn, allowedTypes and allowedValues and StoredValue
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
125 The actual Value of the JobProperty is (statusOn AND StoredValue)
133 _log=Logging.logging.getLogger(
'JobProperty ::')
134 _nInstancesContextDict=dict()
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.
142 if jobPropertiesDisallowed:
143 raise RuntimeError(
"JobProperty should not be called in pure CA config")
145 context_name=context+
'.'+self.__class__.__name__
146 if not (context_name
in self.__class__._nInstancesContextDict.keys()):
147 self.__class__._nInstancesContextDict[context_name]=self
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__()')
159 if isinstance(rhs, JobProperty):
163 return self() == rhs()
167 if isinstance(rhs, JobProperty):
171 return self() < rhs()
191 """ A place-holder for actions to be taken at the time
192 the JobProperty.StoredValue is set or JobProperty.statusOn
200 """ A place-holder for actions to be taken at the time
201 the JobProperty.statusOn is set to False.
208 """ Sets statusOn equals to True.
211 self.__dict__[
'statusOn']=
True
217 """ Sets statusOn equals to False.
220 self.__dict__[
'statusOn']=
False
226 """ lock the property
231 """ unlock the property
234 self.
_log.warning(
'The property %s is being unlocked ',
246 if hasattr(self, name):
247 if name==
'StoredValue' and not(self.
_locked):
256 self.__dict__[name] = n_value
259 self.__dict__[name] = n_value
260 if isinstance(n_value, bool)
and n_value
is False:
266 ' %s is not the expected type for: %s' %
271 ' %s is not the expected type and/or the value is not allowed for: %s' %
274 elif name ==
'StoredValue' and self.
_locked:
277 self.__dict__[name] = n_value
278 elif name ==
'__name__' or name ==
'_context_name':
279 self.__dict__[name] = n_value
281 raise AttributeError(
"JobProperty:: You cannot add attributes to %s" % self)
284 """ Sets the value of the JobProperty .
286 MyJobProperty.set_Value(NewValue)
290 MyJobProperty=NewValue
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.
300 """ Gets the value of the job property.
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.
308 obj_p=object.__getattribute__(self,
'StoredValue')
309 if isinstance(obj_p,
type(
True)):
315 self.
_log.warning(
'You are attempting to access the job'+
320 """ Sets the value of the JobProperty and lock it in one command .
326 """check whether a flag has been modified or if it is still containing
329 val = self.__getattribute__(
'StoredValue')
330 dft = self.__class__.StoredValue
336 """ Prints the documentation available for the JobProperty.
337 together with the actual value, values allowed and types
340 self.
_log.
info(
'### Help for the class %s ###',
346 print (
'## default Value:', self.__class__.StoredValue )
348 self.
_log.
info(
'### End of the help for the class %s ###',
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
359 stored = self.__getattribute__(
'StoredValue')
360 default = self.__class__.StoredValue
362 tbp =
'%s' % pprint.pformat(stored)
364 tbp=
'%s (Stored: %s)' %(pprint.pformat(derived),pprint.pformat(stored))
366 tbp=
'%s (Default: %s)' %(tbp,pprint.pformat(default))
369 tbp =
'Off : %s ' % tbp
375 """ Prints the information of the JobProperty
377 The available options are: 'minimal','full','tree','tree&value','tree&valuenondefault'
380 obj_p=object.__getattribute__(self,
'StoredValue')
393 self.
_log.
info(
" %s-> %s = %s ",indent,
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",
409 self.__getattribute__(
'StoredValue'),
411 'allowedValues :',av,
412 'default value :', self.__class__.StoredValue,
415 'StoredValue :',pprint.pformat(obj_p))
417 print (
' |'+indent+
' '+self.
__name__)
418 elif(mode.startswith(
'tree&value')):
419 if mode==
'tree&value':
421 elif mode==
'tree&valuenondefault':
427 raise RuntimeError(
"This is a non valid print mode %s " % (mode,))
429 print (
' |'+indent+
' '+self.
__name__+
" = "+\
433 elif(mode==
'print_v'):
434 return ' |'+indent+
' '+self.
__name__+
" = "+\
439 raise ValueError(
'Unknow mode, possible modes are: '
440 'minimal, full, tree, tree&value ')
445 """ Container for the JobProperties.
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
452 A JobPropertyContainer can contain other JobProperty
453 containers, that can be added using the "add_Container"
455 There is a top global job properties container instance
456 which is called "jobproperties" that has to be used as starting
460 _log=Logging.logging.getLogger(
'JobPropertyContainer::')
465 """ Each JobPropertyContainer has only one possible instance
469 context_name=self.__class__.__name__
471 context_name=context+
'.'+self.__class__.__name__
472 if not (context_name
in self.__class__._nInstancesContextList):
473 self.__class__._nInstancesContextList.append(context_name)
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__()')
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)):
491 errString=
"JobPropertyContainer:: %s does not have property %s" % (self.
_context_name, name)
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]
500 raise AttributeError(errString)
502 protected=hasattr(self.__dict__[name],
'_context_name')
506 self.__dict__[name] = n_value
508 property_obj=self.__dict__.
get(name)
509 property_obj.StoredValue=n_value
510 property_obj.statusOn=
True
517 print_view=
' [-]'+self.
__name__+
'\n'+
' | '+
'\n'
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'):
525 for i
in range(m._context_name.count(
'.')-1):
527 print_view+=
' /'+indent+
'> ## '+m.__name__+
' ## '+
'\n'
528 print_view+=m.print_JobProperties(
'print_v')
537 """ Prints the documentation generated with the JobProperty
540 self.
_log.
info(
'### Help for the class %s ###',
543 self.
_log.
info(
'### End of the help for the class %s ###',
547 """ Import modules with JobProperties specific to a given job
550 The new specific set of JobProperties added must have a name
551 without '_' and subclass the base class "JobProperty".
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(),\
561 traceback.print_exc()
562 self.
_log.
error(
" import_JobProperties: No module named %s",
568 if(not(p.match(i))
and
569 (i !=
'JobPropertyContainer' and i!=
'JobProperty' and
570 i !=
'jobproperties')):
575 """ OBSOLETE: Use import_JobProperties
577 Import modules with JobProperties specific to a given job
580 The new specific set of JobProperties added must have a name
581 without '_' and subclass the base class "JobProperty".
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
587 self.
_log.warning(
'OBSOLETE method: use import_JobProperties')
591 """ Adds a container of JobProperties of the type
592 JobPropertyContainer to the existing container.
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__,
600 self.
_log.warning(
'The container %s is already in %s',
601 new_container.__name__,self.
__name__)
603 self.
_log.
error(
'You are not adding a JobPropertyContainer ')
606 """ Add one JobProperty to the present container.
608 The new JobProperty added must have a name
609 without '_' and subclass the base class "JobProperty".
611 if issubclass(new_flag,JobProperty):
612 if not(new_flag.__name__
in self.__dict__.
keys()):
615 self.
_log.warning(
'The flag %s is already in %s',
618 self.
_log.
error(
'You are not adding a JobProperty ')
621 """ Deletes one JobProperty from the present container.
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',
631 self.
_log.
info(
'The JobProperty %s is not defined here',
635 """ Deletes one sub-container of the present container.
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__)
645 self.
_log.
info(
'The JobProperty Container %s is not defined here',
646 del_container.__name__)
648 """ Locks the Values of the JobProperties
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()
655 elif hasattr(j_obj,
'_locked'):
657 self.
_log.
info(
'The JobProperty Container %s is locked',
661 """ Unlocks the Values of the JobProperties
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()
668 elif hasattr(j_obj,
'_locked'):
670 self.
_log.warning(
'The JobProperty Container %s is being unlocked ',
674 """Prints all the JobProperties in the container.
676 It will print also the JobProperties within the sub-containers
677 present in the container.
679 The available options are: 'minimal','full','tree','tree&value','tree&valuenondefault'
684 if (mode==
'tree&valuenondefault'):
685 additionalinfo=
"(Only non default values)"
686 if mode !=
"minimal":
687 additionalinfo+=
"(X indicates locked properties)"
689 self.
_log.
info(
"### Printing the job properties container %s %s ###",
692 if(mode==
'tree' or mode.startswith(
'tree&value')):
695 elif(mode==
'print_v'):
696 print_view+=
' [-]'+self.
__name__+
'\n'+
' | '+
'\n'
701 m=self.__dict__.
get(k)
702 if hasattr(m,
'print_JobProperty'):
703 m.print_JobProperty(mode)
705 print_view+=
str(m)+
'\n'
706 elif hasattr(m,
'print_JobProperties'):
708 for i
in range(m._context_name.count(
'.')-1):
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'
715 self.
_log.
info(
' /'+indent+
'> ## '+m.__name__+
' ## ')
718 print_view+=m.print_JobProperties(mode)
720 m.print_JobProperties(mode)
725 self.
_log.
info(
"### Ends the job properties container %s ###",
729 """ It can be used to set several job properties in different
730 JobContainers in one step.
733 The expected data must be a dict as for example:
735 data={'JobProperties.SimFlags':{'init_Level':2,'SeedsG4':.98},
736 'JobProperties.Digitization':{'writeMuonDigit':False}
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",
751 self.
_log.warning(
"The JobProperty %s does not exist",
754 raise ValueError(
'The received data is has not the expected'
759 return object.__getattribute__(self, name)
760 except AttributeError:
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)
776 """ The global job properties container.
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.
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
788 jobproperties=JobProperties()
794 """ Saves the "jobproperties" container of JobProperties.
797 if not (file_name.__contains__(os.sep)) :
798 file_name=os.getcwd()+os.sep+file_name
799 f=
open(file_name,
'w')
802 pickle.dump(jobproperties,f)
805 print (
'It is not possible to save the jobproperties ')
807 """ Loads the "jobproperties" container of JobProperties.
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)
815 print (
'It is not possible to load the jobproperties ')