Gaudi Framework, version v22r4

Home   Generated: Fri Sep 2 2011

Configurable.py

Go to the documentation of this file.
00001 # File: AthenaCommon/python/Configurable.py
00002 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
00003 # Author: Martin Woudstra (Martin.Woudstra@cern.ch)
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 ### data ---------------------------------------------------------------------
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 ## for messaging
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 ## Allow references to options  as in old style
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         # late binding for property references
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             # ignore the error if we cannot resolve the name yet
00081             return self
00082         except AttributeError:
00083             # ignore the error if we cannot resolve the attribute yet
00084             return self
00085 
00086 ### base class for configurable Gaudi algorithms/services/algtools/etc. ======
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     ## for detecting the default name
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',           # controlled components, e.g. private AlgTools
00106        '__tools',              # private AlgTools  (#PM-->)
00107        '_name',                # the (unqualified) component name
00108        '_inSetDefaults',       # currently setting default values
00109        '_initok',              # used to enforce base class init
00110        '_setupok'              # for debugging purposes (temporary)
00111     )
00112 
00113     allConfigurables = {}      # just names would do, but currently refs to the actual
00114     configurableServices = {}  # just names would do, but currently refs to the actual
00115                                # configurables is needed  for (temporary) backwards
00116                                # compatibility; will change in the future
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         # try to get the name of the Configurable (having a name is compulsory)
00126         if 'name' in kwargs:
00127         # simple keyword (by far the easiest)
00128             name = kwargs[ 'name' ]
00129         elif 'name' in cls.__init__.func_code.co_varnames:
00130         # either positional in args, or default
00131             index =  list(cls.__init__.func_code.co_varnames).index( 'name' )
00132             try:
00133              # var names index is offset by one as __init__ is to be called with self
00134                 name = args[ index - 1 ]
00135             except IndexError:
00136              # retrieve default value, then
00137                 name = cls.__init__.func_defaults[ index - (len(args)+1) ]
00138         else:
00139         # positional index is assumed (will work most of the time)
00140             try:
00141                 name = args[1]    # '0' is for self
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         # unnamed, highly specialized user code, etc. ... unacceptable
00153             raise TypeError( 'could not retrieve name from %s.__init__ arguments' % cls.__name__ )
00154 
00155         # Handle the case of global tools to prepend ToolSvc in the name.
00156         # This is needed for compatibility with old JobOptions files being read
00157         if issubclass( cls, ConfigurableAlgTool) and '.' not in name :
00158             name = 'ToolSvc.' + name
00159 
00160         # close backdoor access to otherwise private subalgs/tools
00161         #PM if 0 <= name.find( '.' ):
00162         #PM # temp protection for old style types
00163         #PM   from OldStyleConfig import GenericConfigurable
00164         #PM   if not issubclass( cls, GenericConfigurable ): # except raised for new types only
00165         #PM      raise NameError( '"%s": backdoor access to private configurables not allowed' % name )
00166 
00167         # ordinary recycle case
00168         if name in cls.configurables:
00169             conf = cls.configurables[ name ]
00170             if name != argname:      # special case: user derived <-> real ... make same
00171                 cls.configurables[ conf.getType() ] = conf
00172             #---PM: Initialize additional properties
00173             for n,v in kwargs.items():
00174                 if n != "name": # it should not be confused with a normal property
00175                     setattr(conf, n, v)
00176             if not cls._configurationLocked and not "_enabled" in kwargs and isinstance(conf, ConfigurableUser):
00177                 # Ensure that the ConfigurableUser gets enabled if nothing is
00178                 # specified in the constructor.
00179                 setattr(conf, "_enabled", True)
00180             return conf
00181 
00182         # a couple of special cases (note that these cases don't mix)
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                 # support for old-style name as type/name lookup where name==type
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             # this is the opposite of the above special case
00196                 return cls.configurables[ i_name ]
00197 
00198         # the following is purely for debugging support and should realistically bomb
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:                    # wrong type used?
00203             if conf.__class__ is ConfigurableGeneric :
00204                 #  If the instance found is ConfigurableGeneric then
00205                 #  we create a new one with the proper type and fill with
00206                 #  the contents of the generic one
00207                 newconf = object.__new__( cls )
00208                 cls.__init__( newconf, *args, **kwargs )
00209                 #  initialize with the properties of generic configurable
00210                 #  (we map the names of the properties to lowercase versions because
00211                 #  old options are not case sensitive)
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                 #  will be an actual error in the future (now only report as such)
00226                 log.error( 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
00227                 name, conf.__class__.__name__, cls.__name__, error_explanation )
00228                 #  in the future:
00229                 #  return None             # will bomb on use (or go unharmed on non-use)
00230                 #  for now, allow use through allConfigurables lookup
00231                 #---PM: Initialize additional properties
00232                 for n,v in kwargs.items():
00233                     setattr(conf, n, v)
00234                 return conf
00235 
00236         # still here: create a new instance and initialize it
00237         conf = object.__new__(cls)
00238         cls.__init__( conf, *args, **kwargs )
00239 
00240         # update normal, per-class cache
00241         cls.configurables[ name ] = conf
00242 
00243         for base in cls.__bases__:
00244             if base.__name__ == 'ConfigurableService':
00245                 cls.configurableServices[ name ] = conf
00246 
00247         # update generics super-cache, if needed
00248         cls.allConfigurables[ name ] = conf
00249         #-->PM#if hasattr( cls, 'getType' ) and name.find('/') < 0:
00250         #-->PM#   cls.allConfigurables[ cls.getType() + '/' + name ] = conf
00251 
00252         return conf
00253 
00254     def __init__( self, name = DefaultName ):
00255         # check class readiness, all required overloads should be there now
00256         klass = self.__class__
00257 
00258         # this is an abstract class
00259         if klass == Configurable:
00260             raise TypeError, "%s is an ABC and can not be instantiated" % str(Configurable)
00261 
00262         # the following methods require overloading
00263         #NOT YET  meths = { 'getServices'   : 1,    # retrieve list of services to configure
00264         meths = { 'getDlls'       : 1,    # provide list of Dlls to load
00265                   'getGaudiType'  : 1,    # return string describing component class
00266                   'getHandle'     : 1 }   # provide access to C++ side component instance
00267 #                'getType'       : 1 }   # return the type of the actual C++ component
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             # in addition, verify the number of arguments w/o defaults
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         # for using this Configurable as a (Gaudi) sequence
00282         self.__children = []
00283         self.__tools = {}
00284 
00285         # know who we are
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         # set to True when collecting defaults, False otherwise
00295         self._inSetDefaults = False
00296 
00297         # for later, in case __init__ itself is overridden
00298         self._initok = True
00299 
00300         # for debugging purposes (temporary)
00301         self._setupok = False
00302 
00303     # pickle support
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     # to allow a few basic sanity checks, as well as nice syntax
00327     def __len__( self ):
00328         return len( self.__children )
00329 
00330     def __iter__( self ):
00331         return iter( self.__children )
00332 
00333     # ownership rules of self through copying
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                   # means property was not set for self
00343 
00344         for c in self.__children:
00345             newconf += c              # processes proper copy semantics
00346 
00347         return newconf
00348 
00349     # hierarchy building, and ownership rules of children
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             # prevent type mismatches
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             # filters dupes; usually "ok" (backdoor should catch them)
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:         # support for tool properties
00374                     descr.__set__( self, cc )
00375                 else:
00376                     setattr( self, cc.getName(), cc )
00377             except AttributeError:
00378                 pass              # to allow free addition of tools/subalgorithms
00379 
00380         return self
00381 
00382     def __getattr__( self, attr ):  # until ToolProperties exist ...
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         # remove as property, otherwise try as child
00403         try:
00404             # remove history etc., then reset to default (in case set before)
00405             prop = self._properties[ attr ]
00406             prop.__delete__( self )
00407             prop.__set__( self, prop.default )
00408             return               # reaches here? was property: done now
00409         except KeyError:
00410             pass
00411         # otherwise, remove the private tool
00412         if attr in self.__tools :
00413             del self.__tools[attr]
00414 
00415         # otherwise, remove child, if one is so named
00416         for c in self.__children:
00417             if c.getName() == attr:
00418                 self.__children.remove( c )
00419 
00420         # potentially, there are left over caches (certain user derived classes)
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     # called by __iadd__; determines child copy semantics
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                 # temporary backdoor resolution for compatibility
00460                 log.error( str(e) + '%s', error_explanation )
00461                 ccbd = cc.configurables[ cc.getJobOptName() ]
00462 
00463                 # merge properties, new over pre-existing
00464                 for proxy in self._properties.values():
00465                     if proxy.history.has_key( cc ):
00466                         proxy.__set__( ccbd, proxy.__get__( cc ) )
00467 
00468                 # consolidate
00469                 cc = ccbd
00470         return cc
00471 
00472     def getChildren( self ):
00473         return self.__children[:]    # read only
00474 
00475     def getTools( self ):
00476         return self.__tools.values()    # read only
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       # by ref, for compatibility
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         # add private configurable properties (also inside handles)
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                     # only setup private arrays
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         # add explicit children
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         # make sure base class init has been called
00531         if not hasattr(self,'_initok') or not self._initok:
00532         # could check more, but this is the only explanation
00533             raise TypeError, \
00534                "Configurable.__init__ not called in %s override" % self.__class__.__name__
00535 
00536 #      log.debug("calling setup() on " + self.getFullJobOptName())
00537 
00538         # setup self: this collects all values on the python side
00539         self.__setupServices()
00540         self.__setupDlls()
00541         self.__setupDefaults()
00542 
00543         # setup children
00544         for c in self.getAllChildren():
00545             c.setup()
00546 
00547         # now get handle to work with for moving properties into the catalogue
00548         handle = self.getHandle()
00549         if not handle:
00550             log.debug( 'no handle for %s: not transporting properties', self._name )
00551             return                    # allowed, done early
00552 
00553         # pass final set of properties on to handle on the C++ side or JobOptSvc
00554         for name in self._properties.keys():
00555             if hasattr( self, name ): # means property has python-side value/default
00556                 setattr( handle, name, getattr(self,name) )
00557 
00558         # for debugging purposes
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()           # compatibility
00600 
00601     @classmethod
00602     def getDefaultProperties( cls ):
00603         class collector:
00604             pass
00605 
00606         # user provided defaults
00607         c = collector()
00608         cls.setDefaults( c )
00609 
00610         # defaults from C++
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         # user provided defaults
00623         c = collector()
00624         cls.setDefaults( c )
00625 
00626         if name in c.__dict__:
00627             return c.__dict__[ name ]
00628 
00629         # defaults from C++
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 # no default found
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 ):               # full hierachical name
00681         return self.getName()
00682 
00683     def isPublic( self ):
00684         return True
00685 
00686     # for a couple of existing uses out there
00687     def jobOptName( self ):
00688         log.error( "jobOptName() is deprecated, use getJobOptName() instead for consistency%s",
00689                    error_explanation )
00690         return self.getJobOptName()           # compatibility
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                     # clone the values of the properties for basic types
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              # processes proper copy semantics
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             # this is to avoid that the property hides the tool
00773             setattr(self,name,self.__tools[name])
00774 
00775     def _isInSetDefaults( self ):
00776         return self._inSetDefaults
00777 
00778     def __setupServices( self ):
00779         #svcs = self.getServices()
00780         #if not svcs:
00781         svcs = []
00782         #elif type(svcs) == types.StringType:
00783         #   svcs = [ svcs ]
00784 
00785         import __main__
00786         for svc in svcs:
00787             handle = __main__.Service( svc )
00788             # services should be configurables as well, but aren't for now
00789             # handle.setup()
00790 
00791             # allow Configurable to make some changes
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         # set handle defaults flags to inform __setattr__ that it is being
00808         # called during setDefaults of the concrete Configurable
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)# - len(indentStr)
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)# - len(indentStr)
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  # to print some info depending on output level
00832         indentStr = indent*Configurable.indentUnit
00833         # print header
00834         title = self.getPrintTitle()
00835         # print line to easily see start-of-configurable
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         # print own properties
00843         props = self.getProperties()
00844         defs = self.getDefaultProperties()
00845         if not props:
00846             rep += indentStr + '|-<no properties>' + os.linesep
00847         else:
00848             # get property name with
00849             nameWidth = 0
00850             for p in props.keys():
00851                 nameWidth=max(nameWidth,len(p))
00852             for p, v in props.items():
00853                 # start with indent and property name
00854                 prefix = indentStr + '|-%-*s' % (nameWidth,p)
00855                 # add memory address for debugging (not for defaults)
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                 # add value and default
00863                 default = defs.get(p)
00864                 if v == Configurable.propertyNoValue:
00865                     # show default value as value, and no extra 'default'
00866                     strVal = repr(default)
00867                     strDef = None
00868                 else:
00869                     # convert configurable to handle
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"): # the default may not be a GaudiHandle (?)
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                 # add the value
00886                 line = prefix + ' = ' + strVal
00887                 # add default if present
00888                 if strDef is not None:
00889                     # put default on new line if too big
00890                     if len(line) + len(strDef) > Configurable.printHeaderWidth:
00891                         line += os.linesep + indentStr + '| ' + (len(prefix)-len(indentStr)-3)*' '
00892                     line += '  (default: %s)' % (strDef,)
00893                 # add the line to the total string
00894                 rep += line + os.linesep
00895                 # print out full private configurables
00896 ##              if isinstance(v,Configurable) and not v.isPublic():
00897 ##                  rep += v.__str__( indent + 1 ) + os.linesep
00898 ##              elif isinstance(v,GaudiHandleArray):
00899 ##                  for vi in v:
00900 ##                     if isinstance(vi,Configurable) and not vi.isPublic():
00901 ##                         rep += vi.__str__( indent + 1 ) + os.linesep
00902 
00903         # print configurables + their properties, or loop over sequence
00904 ##      for cfg in self.__children:
00905         for cfg in self.getAllChildren():
00906             rep += cfg.__str__( indent + 1, '|=' ) + os.linesep
00907 
00908         # print line to easily see end-of-configurable. Note: No linesep!
00909         rep += Configurable._printFooter( indentStr, title )
00910         return rep
00911 
00912 ### classes for generic Gaudi component ===========
00913 class DummyDescriptor( object ):
00914     def __init__( self, name ):
00915         self.__name__ = name        # conventional
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     #__slots__ = { }
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                 # algorithms are always shared
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         # filter private (user) variables
00940         if name[0] == '_':
00941             super( ConfigurableGeneric, self ).__setattr__( name, value )
00942             return
00943 
00944         # filter configurable types
00945         if isinstance( value, Configurable ):
00946             self.__dict__[ name ] = value
00947             return
00948 
00949         # assume all the rest are properties
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 ### base classes for individual Gaudi algorithms/services/algtools ===========
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 : ]   # strips class
00968 
00969     def __deepcopy__( self, memo ):
00970         return self                 # algorithms are always shared
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                 # services are always shared
00988 
00989     def copyChild( self, child ):
00990         return child                # full sharing
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         # called on conversion to a string property for the jocat
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             # Public tools must have ToolSvc as parent
01014             self._name = "ToolSvc." + self._name
01015         name = self.getName()
01016         name = name[ name.find('/')+1 : ]   # strips class, if any
01017         self._jobOptName = name
01018 
01019     def getHandle( self ):
01020         # iAlgTool isn't useful, unless one knows for sure that the tool exists
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 #       print "ConfigurableAlgTool.setParent(%s@%x,%r)" % (self.getName(),id(self),parentName)
01041 #       print "Calling stack:"
01042 #       import traceback
01043 #       traceback.print_stack()
01044         # propagate parent to AlgTools in children
01045         for c in self.getAllChildren():
01046             if isinstance(c,ConfigurableAlgTool): c.setParent( parentName )
01047 
01048         # update my own parent
01049         name = self.getName()
01050         name = name[name.rfind('.')+1:] # Name of the instance
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         # called on conversion to a string property for the jocat
01074         return self.getFullName()
01075 
01076     def getFullName( self ) :
01077         # for Tools, the "full name" means "Type/LocalName",
01078         # without the names of the parents
01079         name = self.getName()
01080         # strip off everything before the last '.'
01081         name = name[name.rfind('.')+1:]
01082         return str( self.getType() + '/' + name )
01083 
01084 
01085 ### FIXME: this is just a placeholder, waiting for a real implementation
01086 ###        It is sufficient to get us going... (and import a PkgConf which
01087 ###        happens to contain an Auditor...)
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 : ]   # strips class, if any
01096         self._jobOptName = name
01097 
01098     def getHandle( self ):
01099         # iAlgTool isn't useful, unless one knows for sure that the tool exists
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     # called on conversion to a string property for the jocat
01110         return self.getType() + '/' + self.getName()
01111 
01112 class ConfigurableUser( Configurable ):
01113     __slots__ = { "__users__": [],
01114                   "__used_instances__": [],
01115                   "_enabled": True }
01116     ## list of ConfigurableUser classes this one is going to modify in the
01117     #  __apply_configuration__ method.
01118     #  The list may contain class objects, strings representing class objects or
01119     #  tuples with the class object (or a string) as first element and the instance
01120     #  name as second element.
01121     #  If the instance name is None or not present, the function _instanceName()
01122     #  is used to determine the name of the instance (the default implementation
01123     #  returns "<this name>_<other name>".
01124     __used_configurables__ = []
01125     ## list of ConfigurableUser classes this one is going to query in the
01126     #  __apply_configuration__ method
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         # Needed to retrieve the actual class if the declaration in __used_configurables__
01136         # and  __queried_configurables__ is done with strings.
01137         from GaudiKernel.ConfigurableDb import getConfigurable as confDbGetConfigurable
01138 
01139         # Set the list of users of the used configurables
01140         # 
01141         self.__used_instances__ = []
01142         for used in self.__used_configurables__:
01143             # By default we want to use the default name of the instances
01144             # for the used configurables
01145             used_name = Configurable.DefaultName
01146             # If the entry in the list is a tuple, we need a named instance
01147             if type(used) is tuple:
01148                 used, used_name = used # we re-set used to re-use the code below
01149                 if not used_name:
01150                     used_name = self._instanceName(used)
01151             # Check is 'used' is a string or not
01152             if type(used) is str:
01153                 used_class = confDbGetConfigurable(used)
01154             else:
01155                 used_class = used
01156             # Instantiate the configurable that we are going to use 
01157             try:
01158                 inst = used_class(name = used_name, _enabled = False)
01159             except AttributeError:
01160                 # This cover the case where the used configurable is not a
01161                 # ConfigurableUser instance, i.e. id doesn't have the attribute
01162                 # '_enabled'.
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__"): # allow usage of plain Configurables
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__"): # allow usage of plain Configurables
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         # transform 'others' to a list of configurable instances
01224         if others is None:
01225             others = self.__used_instances__
01226         elif type(others) not in [ list, tuple ] :
01227             others = [ others ]
01228         # these can be computed before the loop
01229         local_is_set = self.isPropertySet(name)
01230         value = self.getProp(name)
01231         # loop over the others that do have 'name' in their slots
01232         for other in [ o for o in others if name in o.__slots__ ]:
01233             # If self property is set, use it
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             # If not, and other property also not set, propagate the default
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                         # Special case for list and dictionaries:
01248                         # also set the property to the same value of the default (copy)
01249                         other.setProp(name, otherType(value))
01250                 else:
01251                     other.setProp(name, value)
01252             # If not set and other set, do nothing
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             # use all the non-private slots
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                     # ensure that the instances retrieved through the method are
01302                     # enabled
01303                     i._enabled = True 
01304                 return i
01305         raise KeyError(name)
01306 
01307 # list of callables to be called after all the __apply_configuration__ are called.
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     # Avoid double calls
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 # needed to detect dependency loops
01344     while applied and confUsers:
01345         newConfUsers = [] # list of conf users that cannot be applied yet
01346         applied = False
01347         for c in confUsers:
01348             if hasattr(c,"__users__") and c.__users__:
01349                 newConfUsers.append(c) # cannot use this one yet
01350             else: # it does not have users or the list is empty
01351                 applied = True
01352                 # the ConfigurableUser is enabled if it doesn't have an _enabled
01353                 # property or its value is True
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                     # tells the used configurables that they are not needed anymore
01363                     c.__detach_used__()
01364         confUsers = newConfUsers # list of C.U.s still to go
01365     if confUsers:
01366         # this means that some C.U.s could not be applied because of a dependency loop
01367         raise Error("Detected loop in the ConfigurableUser "
01368                     " dependencies: %r" % [ c.name()
01369                                             for c in confUsers ])
01370     # Call post-config actions
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" ] # Exclude ConfigurableUser instances
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     # FIXME: (MCl) this is needed because instances of ConfigurableGeneric are not
01393     #        migrated to the correct class when this is known.
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()
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Fri Sep 2 2011 16:24:40 for Gaudi Framework, version v22r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004