00001
00002
00003
00004
00005 import copy, string, types, os
00006 from inspect import isclass
00007 import GaudiKernel.ConfigurableMeta as ConfigurableMeta
00008 from GaudiKernel.Constants import error_explanation, \
00009 VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL
00010 from GaudiKernel.PropertyProxy import PropertyProxy
00011 from GaudiKernel.GaudiHandles import *
00012
00013
00014 __all__ = [ 'Configurable',
00015 'ConfigurableAlgorithm',
00016 'ConfigurableAlgTool',
00017 'ConfigurableAuditor',
00018 'ConfigurableService',
00019 'ConfigurableUser',
00020 'VERBOSE','DEBUG','INFO', 'WARNING', 'ERROR', 'FATAL',
00021 'appendPostConfigAction', 'removePostConfigAction' ]
00022
00023
00024 import logging
00025 log = logging.getLogger( 'Configurable' )
00026
00027 def expandvars(data):
00028 """
00029 Expand environment variables "data".
00030 Data can be string, list, tuple and dictionary. For collection, all the
00031 contained strings will be manipulated (recursively).
00032 """
00033 import os.path
00034 typ = type(data)
00035 if typ is str:
00036 return os.path.expandvars(data)
00037 elif typ in [list, tuple]:
00038 collect = []
00039 for i in data:
00040 collect.append(expandvars(i))
00041 return typ(collect)
00042 elif typ is dict:
00043 collect = {}
00044 for k in data:
00045 collect[expandvars(k)] = expandvars(data[k])
00046 return collect
00047 return data
00048
00049 class Error(RuntimeError):
00050 """
00051 Error occurred in the configuration process.
00052 """
00053 pass
00054
00055
00056 class PropertyReference(object):
00057 def __init__(self,propname):
00058 self.name = propname
00059 def __repr__(self):
00060 return "@%s"%self.name
00061 def __resolve__(self):
00062
00063 retval = None
00064 refname, refprop = self.name.rsplit('.',1)
00065 if refname in Configurable.allConfigurables:
00066 conf = Configurable.allConfigurables[refname]
00067 retval = getattr(conf,refprop)
00068 if hasattr(retval,"getFullName"):
00069 retval = retval.getFullName()
00070 else:
00071 raise NameError("name '%s' not found resolving '%s'"%(refname,self))
00072 return retval
00073 def getFullName(self):
00074 """This function allow transparent integration with
00075 Configurable.getValuedProperties.
00076 """
00077 try:
00078 return self.__resolve__()
00079 except NameError:
00080
00081 return self
00082 except AttributeError:
00083
00084 return self
00085
00086
00087 class Configurable( object ):
00088 """Base class for Gaudi components that implement the IProperty interface.
00089 Provides most of the boilerplate code, but the actual useful classes
00090 are its derived ConfigurableAlgorithm, ConfigurableService, and
00091 ConfigurableAlgTool."""
00092
00093
00094 class DefaultName:
00095 pass
00096
00097 propertyNoValue = '<no value>'
00098 indentUnit = '| '
00099 printHeaderWidth=100
00100 printHeaderPre=5
00101
00102 __metaclass__ = ConfigurableMeta.ConfigurableMeta
00103
00104 __slots__ = (
00105 '__children',
00106 '__tools',
00107 '_name',
00108 '_inSetDefaults',
00109 '_initok',
00110 '_setupok'
00111 )
00112
00113 allConfigurables = {}
00114 configurableServices = {}
00115
00116
00117 _configurationLocked = False
00118
00119 def __new__ ( cls, *args, **kwargs ):
00120 """To Gaudi, any object with the same type/name is the same object. Hence,
00121 this is mimicked in the configuration: instantiating a new Configurable
00122 of a type with the same name will return the same instance."""
00123
00124 global log
00125
00126 if 'name' in kwargs:
00127
00128 name = kwargs[ 'name' ]
00129 elif 'name' in cls.__init__.func_code.co_varnames:
00130
00131 index = list(cls.__init__.func_code.co_varnames).index( 'name' )
00132 try:
00133
00134 name = args[ index - 1 ]
00135 except IndexError:
00136
00137 name = cls.__init__.func_defaults[ index - (len(args)+1) ]
00138 else:
00139
00140 try:
00141 name = args[1]
00142 except (IndexError,TypeError):
00143 raise TypeError( 'no "name" argument while instantiating "%s"' % cls.__name__ )
00144
00145 argname = name
00146 if name == Configurable.DefaultName :
00147 if hasattr(cls, 'DefaultedName' ) :
00148 name = cls.DefaultedName
00149 else :
00150 name = cls.getType()
00151 elif not name or type(name) != str:
00152
00153 raise TypeError( 'could not retrieve name from %s.__init__ arguments' % cls.__name__ )
00154
00155
00156
00157 if issubclass( cls, ConfigurableAlgTool) and '.' not in name :
00158 name = 'ToolSvc.' + name
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 if name in cls.configurables:
00169 conf = cls.configurables[ name ]
00170 if name != argname:
00171 cls.configurables[ conf.getType() ] = conf
00172
00173 for n,v in kwargs.items():
00174 if n != "name":
00175 setattr(conf, n, v)
00176 if not cls._configurationLocked and not "_enabled" in kwargs and isinstance(conf, ConfigurableUser):
00177
00178
00179 setattr(conf, "_enabled", True)
00180 return conf
00181
00182
00183 spos = name.find( '/' )
00184 ti_name = None
00185 if spos < 0:
00186 ti_name = "%s/%s" % (name,name)
00187 if ti_name in cls.configurables:
00188
00189 return cls.configurables[ ti_name ]
00190
00191 i_name = None
00192 if spos > 0:
00193 i_name = name[:spos]
00194 if i_name == name[spos+1:] and i_name in cls.configurables:
00195
00196 return cls.configurables[ i_name ]
00197
00198
00199 conf = cls.allConfigurables.get( name, None ) or\
00200 (spos < 0 and cls.allConfigurables.get( ti_name, None )) or\
00201 (spos > 0 and i_name == name[spos+1:] and cls.allConfigurables.get( i_name, None ))
00202 if conf:
00203 if conf.__class__ is ConfigurableGeneric :
00204
00205
00206
00207 newconf = object.__new__( cls )
00208 cls.__init__( newconf, *args, **kwargs )
00209
00210
00211
00212 names = {}
00213 for n in newconf.__slots__:
00214 names[n.lower()] = n
00215 for n in conf._properties:
00216 if names[n.lower()] != n:
00217 log.warning( "Option '%s' was used for %s, but the correct spelling is '%s'"%(n,name,names[n.lower()]) )
00218 setattr(newconf, names[n.lower()], getattr( conf, n ) )
00219 for n,v in kwargs.items():
00220 setattr(newconf, n, v)
00221 cls.configurables[ name ] = newconf
00222 cls.allConfigurables[ name ] = newconf
00223 return newconf
00224 else :
00225
00226 log.error( 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
00227 name, conf.__class__.__name__, cls.__name__, error_explanation )
00228
00229
00230
00231
00232 for n,v in kwargs.items():
00233 setattr(conf, n, v)
00234 return conf
00235
00236
00237 conf = object.__new__(cls)
00238 cls.__init__( conf, *args, **kwargs )
00239
00240
00241 cls.configurables[ name ] = conf
00242
00243 for base in cls.__bases__:
00244 if base.__name__ == 'ConfigurableService':
00245 cls.configurableServices[ name ] = conf
00246
00247
00248 cls.allConfigurables[ name ] = conf
00249
00250
00251
00252 return conf
00253
00254 def __init__( self, name = DefaultName ):
00255
00256 klass = self.__class__
00257
00258
00259 if klass == Configurable:
00260 raise TypeError, "%s is an ABC and can not be instantiated" % str(Configurable)
00261
00262
00263
00264 meths = { 'getDlls' : 1,
00265 'getGaudiType' : 1,
00266 'getHandle' : 1 }
00267
00268
00269 for meth, nArgs in meths.items():
00270 try:
00271 f = getattr( klass, meth ).im_func
00272 except AttributeError:
00273 raise NotImplementedError, "%s is missing in class %s" % (meth,str(klass))
00274
00275
00276 nargcount = f.func_code.co_argcount
00277 ndefaults = f.func_defaults and len(f.func_defaults) or 0
00278 if not nargcount - ndefaults <= nArgs <= nargcount:
00279 raise TypeError, "%s.%s requires exactly %d arguments" % (klass,meth,nArgs)
00280
00281
00282 self.__children = []
00283 self.__tools = {}
00284
00285
00286 if name == Configurable.DefaultName :
00287 if hasattr(self.__class__, 'DefaultedName' ) :
00288 self._name = self.__class__.DefaultedName
00289 else :
00290 self._name = self.getType()
00291 else :
00292 self._name = name
00293
00294
00295 self._inSetDefaults = False
00296
00297
00298 self._initok = True
00299
00300
00301 self._setupok = False
00302
00303
00304 def __getstate__ (self):
00305 dict = {}
00306 for name, proxy in self._properties.items():
00307 try:
00308 dict[ name ] = proxy.__get__( self )
00309 except AttributeError:
00310 pass
00311
00312 dict[ '_Configurable__children' ] = self.__children
00313 dict[ '_Configurable__tools' ] = self.__tools
00314 dict[ '_name' ] = self._name
00315 return dict
00316
00317 def __getnewargs__(self) :
00318 return (self._name,)
00319
00320 def __setstate__ ( self, dict ):
00321 self._initok = True
00322 for n, v in dict.items():
00323 setattr (self, n, v)
00324 return
00325
00326
00327 def __len__( self ):
00328 return len( self.__children )
00329
00330 def __iter__( self ):
00331 return iter( self.__children )
00332
00333
00334 def __deepcopy__( self, memo ):
00335 newconf = object.__new__( self.__class__ )
00336 self.__class__.__init__( newconf, self.getName() )
00337
00338 for proxy in self._properties.values():
00339 try:
00340 proxy.__set__( newconf, proxy.__get__( self ) )
00341 except AttributeError:
00342 pass
00343
00344 for c in self.__children:
00345 newconf += c
00346
00347 return newconf
00348
00349
00350 def __iadd__( self, configs, descr = None ):
00351 if not type(configs) in (list,tuple):
00352 configs = ( configs, )
00353
00354 joname = self.getJobOptName()
00355
00356 for cfg in configs:
00357
00358 if not isinstance( cfg, Configurable ):
00359 raise TypeError( "'%s' is not a Configurable" % str(cfg) )
00360
00361 cc = self.copyChildAndSetParent( cfg, joname )
00362
00363
00364 ccjo = cc.getJobOptName()
00365 for c in self.__children:
00366 if c.getJobOptName() == ccjo:
00367 log.error( 'attempt to add a duplicate ... dupe ignored%s', error_explanation )
00368 break
00369 else:
00370 self.__children.append( cc )
00371
00372 try:
00373 if descr:
00374 descr.__set__( self, cc )
00375 else:
00376 setattr( self, cc.getName(), cc )
00377 except AttributeError:
00378 pass
00379
00380 return self
00381
00382 def __getattr__( self, attr ):
00383
00384 if attr in self.__tools : return self.__tools[attr]
00385
00386 for c in self.__children:
00387 if c.getName() == attr:
00388 return c
00389
00390 raise AttributeError( "'%s' object has no attribute '%s'" % (self.__class__,attr) )
00391
00392 def __setattr__( self, name, value ) :
00393 if self._configurationLocked:
00394 raise RuntimeError("%s: Configuration cannot be modified after the ApplicationMgr has been started."%self.name())
00395 try :
00396 super( Configurable, self ).__setattr__( name, value )
00397 except AttributeError:
00398 raise AttributeError( "Configurable '%s' does not have property '%s'."
00399 % ( self.__class__.__name__, name) )
00400
00401 def __delattr__( self, attr ):
00402
00403 try:
00404
00405 prop = self._properties[ attr ]
00406 prop.__delete__( self )
00407 prop.__set__( self, prop.default )
00408 return
00409 except KeyError:
00410 pass
00411
00412 if attr in self.__tools :
00413 del self.__tools[attr]
00414
00415
00416 for c in self.__children:
00417 if c.getName() == attr:
00418 self.__children.remove( c )
00419
00420
00421 try:
00422 del self.__dict__[ attr ]
00423 except (AttributeError,KeyError):
00424 pass
00425
00426 def __nonzero__(self):
00427 return True
00428
00429
00430 def remove( self, items ):
00431 if type(items) != list and type(items) != tuple:
00432 items = [ items ]
00433
00434 self.__children = [ e for e in self.__children if not e in items ]
00435
00436 def removeAll( self ):
00437 self.remove( self.__children )
00438
00439
00440 def copyChild( self, child ):
00441 return copy.deepcopy( child )
00442
00443 def setParent( self, parentName ):
00444 pass
00445
00446 def getParent( self ):
00447 return ""
00448
00449 def hasParent( self, parent ):
00450 return False
00451
00452 def copyChildAndSetParent(self,cfg,parent):
00453 cc = self.copyChild( cfg )
00454
00455 if hasattr( cc, 'setParent' ) and parent:
00456 try:
00457 cc.setParent( parent )
00458 except RuntimeError, e:
00459
00460 log.error( str(e) + '%s', error_explanation )
00461 ccbd = cc.configurables[ cc.getJobOptName() ]
00462
00463
00464 for proxy in self._properties.values():
00465 if proxy.history.has_key( cc ):
00466 proxy.__set__( ccbd, proxy.__get__( cc ) )
00467
00468
00469 cc = ccbd
00470 return cc
00471
00472 def getChildren( self ):
00473 return self.__children[:]
00474
00475 def getTools( self ):
00476 return self.__tools.values()
00477
00478 def children( self ):
00479 log.error( "children() is deprecated, use getChildren() instead for consistency" )
00480 log.error( "getChildren() returns a copy; to add a child, use 'parent += child'%s",
00481 error_explanation )
00482 return self.__children
00483
00484 def getAllChildren( self ):
00485 """Get all (private) configurable children, both explicit ones (added with +=)
00486 and the ones in the private GaudiHandle properties"""
00487 childs = []
00488
00489 for proxy in self._properties.values():
00490 try:
00491 c = proxy.__get__( self )
00492 except AttributeError:
00493 pass
00494 else:
00495 if isinstance(c,Configurable) and not c.isPublic():
00496 childs.append(c)
00497 elif isinstance(c,GaudiHandle):
00498 try:
00499 conf = c.configurable
00500 except AttributeError:
00501 pass
00502 else:
00503 if not conf.isPublic():
00504 childs.append(conf)
00505 elif isinstance(c,GaudiHandleArray):
00506
00507 if not c.isPublic():
00508 for ci in c:
00509 if isinstance(ci,Configurable):
00510 childs.append(ci)
00511 else:
00512 try:
00513 conf = ci.configurable
00514 except AttributeError:
00515 pass
00516 else:
00517 childs.append(conf)
00518
00519
00520 childs += self.__children
00521 return childs
00522
00523 def getSequence( self ):
00524 elems = []
00525 for c in self.__children:
00526 elems.append( c.getFullName() )
00527 return elems
00528
00529 def setup( self ):
00530
00531 if not hasattr(self,'_initok') or not self._initok:
00532
00533 raise TypeError, \
00534 "Configurable.__init__ not called in %s override" % self.__class__.__name__
00535
00536
00537
00538
00539 self.__setupServices()
00540 self.__setupDlls()
00541 self.__setupDefaults()
00542
00543
00544 for c in self.getAllChildren():
00545 c.setup()
00546
00547
00548 handle = self.getHandle()
00549 if not handle:
00550 log.debug( 'no handle for %s: not transporting properties', self._name )
00551 return
00552
00553
00554 for name in self._properties.keys():
00555 if hasattr( self, name ):
00556 setattr( handle, name, getattr(self,name) )
00557
00558
00559 self._setupok = True
00560
00561 def getProperties( self ):
00562 props = {}
00563 for name, proxy in self._properties.items():
00564 try:
00565 props[ name ] = proxy.__get__( self )
00566 except AttributeError:
00567 props[ name ] = Configurable.propertyNoValue
00568
00569 return props
00570
00571 def getValuedProperties( self ):
00572 props = {}
00573 for name, proxy in self._properties.items():
00574 if self.isPropertySet(name):
00575 value = proxy.__get__( self )
00576 if hasattr(value, 'getFullName') :
00577 value = value.getFullName()
00578 elif type(value) in [list, tuple]:
00579 new_value = []
00580 for i in value:
00581 if hasattr(i, 'getFullName'):
00582 new_value.append(i.getFullName())
00583 else:
00584 new_value.append(i)
00585 value = type(value)(new_value)
00586 elif type(value) is dict:
00587 new_value = {}
00588 for i in value:
00589 if hasattr(value[i], 'getFullName'):
00590 new_value[i] = value[i].getFullName()
00591 else:
00592 new_value[i] = value[i]
00593 value = new_value
00594 props[ name ] = value
00595
00596 return props
00597
00598 def properties( self ):
00599 return self.getProperties()
00600
00601 @classmethod
00602 def getDefaultProperties( cls ):
00603 class collector:
00604 pass
00605
00606
00607 c = collector()
00608 cls.setDefaults( c )
00609
00610
00611 for k,v in cls._properties.items():
00612 if not k in c.__dict__ and hasattr( v, 'default' ):
00613 c.__dict__[ k ] = v.default
00614
00615 return c.__dict__
00616
00617 @classmethod
00618 def getDefaultProperty( cls, name ):
00619 class collector:
00620 pass
00621
00622
00623 c = collector()
00624 cls.setDefaults( c )
00625
00626 if name in c.__dict__:
00627 return c.__dict__[ name ]
00628
00629
00630 try:
00631 v = cls._properties[name]
00632 if hasattr( v, 'default' ):
00633 return v.default
00634 except KeyError:
00635 pass
00636
00637 return None
00638
00639 def getProp(self, name):
00640 """Returns the value of the given property.
00641 """
00642 if hasattr(self, name):
00643 return getattr(self, name)
00644 else:
00645 return self.getDefaultProperties()[name]
00646
00647 def setProp(self, name, value):
00648 """Set the value of a given property
00649 """
00650 return setattr(self, name, value)
00651
00652 def isPropertySet(self, name):
00653 """Tell if the property 'name' has been set or not.
00654
00655 Because of a problem with list and dictionary properties, in those cases
00656 if the value is equal to the default, the property is considered as not
00657 set.
00658 """
00659 if not hasattr(self, name):
00660 return False
00661 else:
00662 try:
00663 default = self.getDefaultProperties()[name]
00664 if isinstance(default, (list, dict)):
00665 value = getattr(self, name)
00666 return value != default
00667 except KeyError:
00668 pass
00669 return True
00670
00671 def getType( cls ):
00672 return cls.__name__
00673
00674 def getName( self ):
00675 return self._name
00676
00677 def name( self ):
00678 return self.getName()
00679
00680 def getJobOptName( self ):
00681 return self.getName()
00682
00683 def isPublic( self ):
00684 return True
00685
00686
00687 def jobOptName( self ):
00688 log.error( "jobOptName() is deprecated, use getJobOptName() instead for consistency%s",
00689 error_explanation )
00690 return self.getJobOptName()
00691
00692 def getFullName( self ) :
00693 return str( self.getType() + '/' + self.getName() )
00694
00695 def getFullJobOptName( self ):
00696 return "%s/%s" % (self.getType(),self.getJobOptName() or self.getName())
00697
00698 def getPrintTitle(self):
00699 return self.getGaudiType() + ' ' + self.getTitleName()
00700
00701 def getTitleName( self ):
00702 if log.isEnabledFor( logging.DEBUG ):
00703 return self.getFullJobOptName()
00704 else:
00705 return self.getFullName()
00706
00707 def setDefaults( cls, handle ):
00708 pass
00709
00710 def clone( self, name = None, **kwargs ) :
00711 if not name :
00712 if hasattr(self, 'DefaultedName' ) : name = self.DefaultedName
00713 else : name = self.getType()
00714
00715 newconf = Configurable.__new__( self.__class__, name )
00716 self.__class__.__init__( newconf, name )
00717
00718 for proxy in self._properties.values():
00719 try :
00720 value = proxy.__get__( self )
00721 if type(value) in [ str, list, dict, tuple ]:
00722
00723 value = type(value)(value)
00724 proxy.__set__( newconf, value )
00725 except AttributeError:
00726 pass
00727
00728 for c in self.__children:
00729 newconf += c
00730
00731 for n , t in self.__tools.items():
00732 newconf.addTool(t, n)
00733
00734 for name, value in kwargs.items():
00735 setattr(newconf, name, value)
00736
00737 return newconf
00738
00739 def splitName( self ) :
00740 fullname = self.getName()
00741 dot = fullname.find('.')
00742 if dot != -1 :
00743 parentname = fullname[:dot]
00744 longname = fullname[dot+1:]
00745 else :
00746 parentname = ''
00747 longname = fullname
00748 dot = longname.find('.')
00749 if dot != -1 :
00750 name = longname[:dot]
00751 else :
00752 name = longname
00753 return parentname, name, longname
00754
00755 def addTool( self, tool, name = None ) :
00756 if isclass(tool) and issubclass(tool, ConfigurableAlgTool):
00757 if name is None:
00758 name = tool.__name__
00759 priv_tool = tool( self.getName()+ '.' + name )
00760 elif isinstance(tool, ConfigurableAlgTool):
00761 if name is None:
00762 name = tool.splitName()[1]
00763 priv_tool = tool.clone( self.getName()+ '.' + name )
00764 else:
00765 if isclass(tool):
00766 classname = tool.__name__
00767 else:
00768 classname = type(tool).__name__
00769 raise TypeError, "addTool requires AlgTool configurable. Got %s type" % classname
00770 self.__tools[name] = priv_tool
00771 if name in self.__slots__:
00772
00773 setattr(self,name,self.__tools[name])
00774
00775 def _isInSetDefaults( self ):
00776 return self._inSetDefaults
00777
00778 def __setupServices( self ):
00779
00780
00781 svcs = []
00782
00783
00784
00785 import __main__
00786 for svc in svcs:
00787 handle = __main__.Service( svc )
00788
00789
00790
00791
00792 if hasattr( self, 'configure' + svc ):
00793 eval( 'self.configure' + svc + '( handle )' )
00794
00795 def __setupDlls( self ):
00796 dlls = self.getDlls()
00797 if not dlls:
00798 dlls = []
00799 elif type(dlls) == types.StringType:
00800 dlls = [ dlls ]
00801
00802 from __main__ import theApp
00803 dlls = filter( lambda d: d not in theApp.Dlls, dlls )
00804 if dlls: theApp.Dlls += dlls
00805
00806 def __setupDefaults( self ):
00807
00808
00809 self._inSetDefaults = True
00810 self.setDefaults( self )
00811 self._inSetDefaults = False
00812
00813 @staticmethod
00814 def _printHeader( indentStr, title ):
00815 preLen = Configurable.printHeaderPre
00816 postLen = Configurable.printHeaderWidth - preLen - 3 - len(title)
00817 postLen = max(preLen,postLen)
00818 return indentStr + '/%s %s %s' % (preLen*'*',title,postLen*'*')
00819
00820 @staticmethod
00821 def _printFooter( indentStr, title ):
00822 preLen = Configurable.printHeaderPre
00823 postLen = Configurable.printHeaderWidth - preLen - 12 - len(title)
00824 postLen = max(preLen,postLen)
00825 return indentStr + '\\%s (End of %s) %s' % (preLen*'-',title,postLen*'-')
00826
00827 def __repr__( self ):
00828 return '<%s at %s>' % (self.getFullJobOptName(),hex(id(self)))
00829
00830 def __str__( self, indent = 0, headerLastIndentUnit=indentUnit ):
00831 global log
00832 indentStr = indent*Configurable.indentUnit
00833
00834 title = self.getPrintTitle()
00835
00836 if indent > 0:
00837 headerIndent = (indent-1)*Configurable.indentUnit + headerLastIndentUnit
00838 else:
00839 headerIndent = ''
00840 rep = Configurable._printHeader( headerIndent, title )
00841 rep += os.linesep
00842
00843 props = self.getProperties()
00844 defs = self.getDefaultProperties()
00845 if not props:
00846 rep += indentStr + '|-<no properties>' + os.linesep
00847 else:
00848
00849 nameWidth = 0
00850 for p in props.keys():
00851 nameWidth=max(nameWidth,len(p))
00852 for p, v in props.items():
00853
00854 prefix = indentStr + '|-%-*s' % (nameWidth,p)
00855
00856 if log.isEnabledFor( logging.DEBUG ):
00857 if v != Configurable.propertyNoValue:
00858 address = ' @%11s' % hex(id(v))
00859 else:
00860 address = 13*' '
00861 prefix += address
00862
00863 default = defs.get(p)
00864 if v == Configurable.propertyNoValue:
00865
00866 strVal = repr(default)
00867 strDef = None
00868 else:
00869
00870 if hasattr(v,"getGaudiHandle"):
00871 vv = v.getGaudiHandle()
00872 else:
00873 vv = v
00874 if isinstance(vv,GaudiHandle) or isinstance(vv,GaudiHandleArray):
00875 strVal = repr(vv)
00876 if hasattr(default,"toStringProperty"):
00877 strDef = repr(default.toStringProperty())
00878 else:
00879 strDef = repr(default)
00880 if strDef == repr(vv.toStringProperty()):
00881 strDef = None
00882 else:
00883 strVal = repr(vv)
00884 strDef = repr(default)
00885
00886 line = prefix + ' = ' + strVal
00887
00888 if strDef is not None:
00889
00890 if len(line) + len(strDef) > Configurable.printHeaderWidth:
00891 line += os.linesep + indentStr + '| ' + (len(prefix)-len(indentStr)-3)*' '
00892 line += ' (default: %s)' % (strDef,)
00893
00894 rep += line + os.linesep
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905 for cfg in self.getAllChildren():
00906 rep += cfg.__str__( indent + 1, '|=' ) + os.linesep
00907
00908
00909 rep += Configurable._printFooter( indentStr, title )
00910 return rep
00911
00912
00913 class DummyDescriptor( object ):
00914 def __init__( self, name ):
00915 self.__name__ = name
00916
00917 def __get__( self, obj, type = None ):
00918 return getattr( obj, self.__name__ )
00919
00920 def __set__( self, obj, value ):
00921 object.__setattr__( obj, self.__name__, value )
00922
00923 class ConfigurableGeneric( Configurable ):
00924
00925
00926 def __init__( self, name = Configurable.DefaultName ):
00927 Configurable.__init__( self, name )
00928 self._name = name
00929 self._properties = {}
00930
00931 def __deepcopy__( self, memo ):
00932 return self
00933
00934 def getGaudiType( self ): return 'GenericComponent'
00935 def getDlls( self ) : pass
00936 def getHandle( self ) : pass
00937
00938 def __setattr__( self, name, value ):
00939
00940 if name[0] == '_':
00941 super( ConfigurableGeneric, self ).__setattr__( name, value )
00942 return
00943
00944
00945 if isinstance( value, Configurable ):
00946 self.__dict__[ name ] = value
00947 return
00948
00949
00950 if not name in self._properties:
00951 self._properties[ name ] = PropertyProxy( DummyDescriptor( name ) )
00952 self._properties[ name ].__set__( self, value )
00953
00954 def getJobOptName( self ): return None
00955
00956
00957
00958 class ConfigurableAlgorithm( Configurable ):
00959 __slots__ = { '_jobOptName' : 0, 'OutputLevel' : 0, \
00960 'Enable' : 1, 'ErrorMax' : 1, 'ErrorCount' : 0, 'AuditAlgorithms' : 0, \
00961 'AuditInitialize' : 0, 'AuditReinitialize' : 0, 'AuditExecute' : 0, \
00962 'AuditFinalize' : 0, 'AuditBeginRun' : 0, 'AuditEndRun' : 0 }
00963
00964 def __init__( self, name = Configurable.DefaultName ):
00965 super( ConfigurableAlgorithm, self ).__init__( name )
00966 name = self.getName()
00967 self._jobOptName = name[ name.find('/')+1 : ]
00968
00969 def __deepcopy__( self, memo ):
00970 return self
00971
00972 def getHandle( self ):
00973 return iAlgorithm( self.getJobOptName() )
00974
00975 def getGaudiType( self ):
00976 return 'Algorithm'
00977
00978 def getJobOptName( self ):
00979 return self._jobOptName
00980
00981
00982 class ConfigurableService( Configurable ):
00983 __slots__ = { 'OutputLevel' : 0, \
00984 'AuditServices' : 0, 'AuditInitialize' : 0, 'AuditFinalize' : 0 }
00985
00986 def __deepcopy__( self, memo ):
00987 return self
00988
00989 def copyChild( self, child ):
00990 return child
00991
00992 def getHandle( self ):
00993 return iService( self._name )
00994
00995 def getGaudiType( self ):
00996 return 'Service'
00997
00998 def getGaudiHandle( self ):
00999 return ServiceHandle( self.toStringProperty() )
01000
01001 def toStringProperty( self ):
01002
01003 return self.getName()
01004
01005
01006 class ConfigurableAlgTool( Configurable ):
01007 __slots__ = { '_jobOptName' : '', 'OutputLevel' : 0, \
01008 'AuditTools' : 0, 'AuditInitialize' : 0, 'AuditFinalize' : 0 }
01009
01010 def __init__( self, name = Configurable.DefaultName ):
01011 super( ConfigurableAlgTool, self ).__init__( name )
01012 if '.' not in self._name:
01013
01014 self._name = "ToolSvc." + self._name
01015 name = self.getName()
01016 name = name[ name.find('/')+1 : ]
01017 self._jobOptName = name
01018
01019 def getHandle( self ):
01020
01021 return iProperty( self.getJobOptName() )
01022
01023 def getGaudiType( self ):
01024 return 'AlgTool'
01025
01026 def getGaudiHandle( self ):
01027 if self.isPublic():
01028 return PublicToolHandle( self.toStringProperty() )
01029 else:
01030 return PrivateToolHandle( self.toStringProperty() )
01031
01032 def getPrintTitle(self):
01033 if self.isPublic():
01034 pop = 'Public '
01035 else:
01036 pop = 'Private '
01037 return pop + Configurable.getPrintTitle(self)
01038
01039 def setParent( self, parentName ):
01040
01041
01042
01043
01044
01045 for c in self.getAllChildren():
01046 if isinstance(c,ConfigurableAlgTool): c.setParent( parentName )
01047
01048
01049 name = self.getName()
01050 name = name[name.rfind('.')+1:]
01051 self._jobOptName = self._name = parentName + '.' + name
01052
01053 def getParent( self ):
01054 dot = self._jobOptName.rfind('.')
01055 if dot != -1:
01056 return self._jobOptName[:dot]
01057 else:
01058 return ""
01059
01060 def hasParent( self, parent ):
01061 return self._jobOptName.startswith( parent + '.' )
01062
01063 def getJobOptName( self ):
01064 return self._jobOptName
01065
01066 def isPublic( self ):
01067 return self.isInToolSvc()
01068
01069 def isInToolSvc( self ):
01070 return self._jobOptName.startswith('ToolSvc.')
01071
01072 def toStringProperty( self ):
01073
01074 return self.getFullName()
01075
01076 def getFullName( self ) :
01077
01078
01079 name = self.getName()
01080
01081 name = name[name.rfind('.')+1:]
01082 return str( self.getType() + '/' + name )
01083
01084
01085
01086
01087
01088 class ConfigurableAuditor( Configurable ):
01089 __slots__ = { '_jobOptName' : 0, 'OutputLevel' : 0, \
01090 'Enable' : 1 }
01091
01092 def __init__( self, name = Configurable.DefaultName ):
01093 super( ConfigurableAuditor, self ).__init__( name )
01094 name = self.getName()
01095 name = name[ name.find('/')+1 : ]
01096 self._jobOptName = name
01097
01098 def getHandle( self ):
01099
01100 return iProperty( self.getJobOptName() )
01101
01102 def getGaudiType( self ):
01103 return 'Auditor'
01104
01105 def getJobOptName( self ):
01106 return self._jobOptName
01107
01108 def toStringProperty( self ):
01109
01110 return self.getType() + '/' + self.getName()
01111
01112 class ConfigurableUser( Configurable ):
01113 __slots__ = { "__users__": [],
01114 "__used_instances__": [],
01115 "_enabled": True }
01116
01117
01118
01119
01120
01121
01122
01123
01124 __used_configurables__ = []
01125
01126
01127 __queried_configurables__ = []
01128 def __init__( self, name = Configurable.DefaultName, _enabled = True, **kwargs ):
01129 super( ConfigurableUser, self ).__init__( name )
01130 for n, v in kwargs.items():
01131 setattr(self, n, v)
01132 self._enabled = _enabled
01133 self.__users__ = []
01134
01135
01136
01137 from GaudiKernel.ConfigurableDb import getConfigurable as confDbGetConfigurable
01138
01139
01140
01141 self.__used_instances__ = []
01142 for used in self.__used_configurables__:
01143
01144
01145 used_name = Configurable.DefaultName
01146
01147 if type(used) is tuple:
01148 used, used_name = used
01149 if not used_name:
01150 used_name = self._instanceName(used)
01151
01152 if type(used) is str:
01153 used_class = confDbGetConfigurable(used)
01154 else:
01155 used_class = used
01156
01157 try:
01158 inst = used_class(name = used_name, _enabled = False)
01159 except AttributeError:
01160
01161
01162
01163 inst = used_class(name = used_name)
01164 self.__addActiveUseOf(inst)
01165 for queried in self.__queried_configurables__:
01166 try:
01167 if type(queried) is str:
01168 queried = confDbGetConfigurable(used)
01169 inst = queried(_enabled = False)
01170 except AttributeError:
01171 inst = queried()
01172 self.__addPassiveUseOf(inst)
01173 def __addActiveUseOf(self, other):
01174 """
01175 Declare that we are going to modify the Configurable 'other' in our
01176 __apply_configuration__.
01177 """
01178 self.__used_instances__.append(other)
01179 if hasattr(other, "__users__"):
01180 other.__users__.append(self)
01181 def __addPassiveUseOf(self, other):
01182 """
01183 Declare that we are going to retrieve property values from the
01184 ConfigurableUser 'other' in our __apply_configuration__.
01185 """
01186 if not isinstance(other, ConfigurableUser):
01187 raise Error("'%s': Cannot make passive use of '%s', it is not a ConfigurableUser" % (self.name(), other.name()))
01188 other.__addActiveUseOf(self)
01189 def getGaudiType( self ):
01190 return 'User'
01191 def getDlls( self ):
01192 return None
01193 def getHandle( self ):
01194 return None
01195
01196 def __detach_used__(self):
01197 """
01198 Remove this ConfigurableUser instance from the users list of the used
01199 instances.
01200 """
01201 for used in self.__used_instances__:
01202 if hasattr(used, "__users__"):
01203 used.__users__.remove(self)
01204
01205 def propagateProperty(self, name, others = None, force = True):
01206 """
01207 Propagate the property 'name' (if set) to other configurables (if possible).
01208 'others' can be:
01209 None:
01210 propagate to all the entries in __used_configurables__
01211 a configurable instance:
01212 propagate only to it
01213 list of configurable instances:
01214 propagate to all of them.
01215
01216
01217 The logic is:
01218 - if the local property is set, the other property will be overwritten
01219 - local property not set and other set => keep other
01220 - local property not set and other not set => overwrite the default for
01221 ConfigurableUser instances and set the property for Configurables
01222 """
01223
01224 if others is None:
01225 others = self.__used_instances__
01226 elif type(others) not in [ list, tuple ] :
01227 others = [ others ]
01228
01229 local_is_set = self.isPropertySet(name)
01230 value = self.getProp(name)
01231
01232 for other in [ o for o in others if name in o.__slots__ ]:
01233
01234 if local_is_set:
01235 if other.isPropertySet(name):
01236 log.warning("Property '%(prop)s' is set in both '%(self)s' and '%(other)s', using '%(self)s.%(prop)s'"%
01237 { "self": self.name(),
01238 "other": other.name(),
01239 "prop": name } )
01240 other.setProp(name, value)
01241
01242 elif not other.isPropertySet(name):
01243 if isinstance(other,ConfigurableUser):
01244 otherType = type(other._properties[name].getDefault())
01245 other._properties[name].setDefault(value)
01246 if otherType in [list, dict]:
01247
01248
01249 other.setProp(name, otherType(value))
01250 else:
01251 other.setProp(name, value)
01252
01253
01254 def propagateProperties(self, names = None, others = None, force = True):
01255 """
01256 Call propagateProperty for each property listed in 'names'.
01257 If 'names' is None, all the properties are propagated.
01258 """
01259 if names is None:
01260
01261 names = [ p for p in self.__slots__ if not p.startswith("_") ]
01262 for n in names:
01263 self.propagateProperty(n, others, force)
01264
01265 def __apply_configuration__(self):
01266 """
01267 Function to be overridden to convert the high level configuration into a
01268 low level one.
01269 The default implementation calls applyConf, which is the method defined
01270 in some ConfigurableUser implementations.
01271 """
01272 return self.applyConf()
01273
01274 def applyConf( self ):
01275 """
01276 Function to be overridden to convert the high level configuration into a
01277 low level one.
01278 """
01279 pass
01280
01281 def _instanceName(self, cls):
01282 """
01283 Function used to define the name of the private instance of a given class
01284 name.
01285 This method is used when the __used_configurables_property__ declares the
01286 need of a private used configurable without specifying the name.
01287 """
01288 if type(cls) is str:
01289 clName = cls
01290 else:
01291 clName = cls.__name__
01292 return "%s_%s" % (self.name(), clName)
01293
01294 def getUsedInstance(self, name):
01295 """
01296 Return the used instance with a given name.
01297 """
01298 for i in self.__used_instances__:
01299 if i.name() == name:
01300 if hasattr(i, "_enabled"):
01301
01302
01303 i._enabled = True
01304 return i
01305 raise KeyError(name)
01306
01307
01308 postConfigActions = []
01309 def appendPostConfigAction(function):
01310 """
01311 Add a new callable ('function') to the list of post-configuration actions.
01312 If the callable is already in the list, it is moved to the end of the list.
01313 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
01314 """
01315 try:
01316 postConfigActions.remove(function)
01317 except:
01318 pass
01319 postConfigActions.append(function)
01320 def removePostConfigAction(function):
01321 """
01322 Remove a collable from the list of post-config actions.
01323 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
01324 """
01325 postConfigActions.remove(function)
01326
01327 _appliedConfigurableUsers_ = False
01328 def applyConfigurableUsers():
01329 """
01330 Call the apply method of all the ConfigurableUser instances respecting the
01331 dependencies. First the C.U.s that are not used by anybody, then the used
01332 ones, when they are not used anymore.
01333 """
01334
01335 global _appliedConfigurableUsers_, postConfigActions
01336 if _appliedConfigurableUsers_:
01337 return
01338 _appliedConfigurableUsers_ = True
01339
01340 confUsers = [ c
01341 for c in Configurable.allConfigurables.values()
01342 if hasattr(c,"__apply_configuration__") ]
01343 applied = True
01344 while applied and confUsers:
01345 newConfUsers = []
01346 applied = False
01347 for c in confUsers:
01348 if hasattr(c,"__users__") and c.__users__:
01349 newConfUsers.append(c)
01350 else:
01351 applied = True
01352
01353
01354 enabled = (not hasattr(c, "_enabled")) or c._enabled
01355 if enabled:
01356 log.info("applying configuration of %s", c.name())
01357 c.__apply_configuration__()
01358 log.info(c)
01359 else:
01360 log.info("skipping configuration of %s", c.name())
01361 if hasattr(c, "__detach_used__"):
01362
01363 c.__detach_used__()
01364 confUsers = newConfUsers
01365 if confUsers:
01366
01367 raise Error("Detected loop in the ConfigurableUser "
01368 " dependencies: %r" % [ c.name()
01369 for c in confUsers ])
01370
01371 for action in postConfigActions:
01372 action()
01373
01374 def getNeededConfigurables():
01375 """
01376 Function to select all and only the configurables that have to be used in
01377 GaudiPython.AppMgr constructor.
01378 This is needed because in Athena the implementation have to be different (the
01379 configuration is used in a different moment).
01380 """
01381 return [ k
01382 for k, v in Configurable.allConfigurables.items()
01383 if v.getGaudiType() != "User" ]
01384
01385 def purge():
01386 """
01387 Clean up all configurations and configurables.
01388 """
01389 for c in Configurable.allConfigurables.values():
01390 c.__class__.configurables.clear()
01391 Configurable.allConfigurables.clear()
01392
01393
01394 ConfigurableGeneric.configurables.clear()
01395 from ProcessJobOptions import _included_files
01396 import os.path, sys
01397 for file in _included_files:
01398 dirname, basname = os.path.split(file)
01399 basname, ext = os.path.splitext(basname)
01400 if basname in sys.modules:
01401 del sys.modules[basname]
01402 _included_files.clear()