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