| The Gaudi Framework v27r1

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

Configurable.py
Go to the documentation of this file.
1 # File: AthenaCommon/python/Configurable.py
2 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
3 # Author: Martin Woudstra (Martin.Woudstra@cern.ch)
4
5 import copy, string, types, os
6 import sys
7 from inspect import isclass
8 import GaudiKernel.ConfigurableMeta as ConfigurableMeta
9 from GaudiKernel.Constants import error_explanation, \
10 VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL
11 from GaudiKernel.PropertyProxy import PropertyProxy
12 from GaudiKernel.GaudiHandles import *
13 from GaudiKernel.DataObjectHandleBase import *
14
15 ### data ---------------------------------------------------------------------
16 __all__ = [ 'Configurable',
17 'ConfigurableAlgorithm',
18 'ConfigurableAlgTool',
19 'ConfigurableAuditor',
20 'ConfigurableService',
21 'ConfigurableUser',
22 'VERBOSE','DEBUG','INFO', 'WARNING', 'ERROR', 'FATAL',
23 'appendPostConfigAction', 'removePostConfigAction' ]
24
25 ## for messaging
26 import logging
27 log = logging.getLogger( 'Configurable' )
28
29 def expandvars(data):
30 """
31 Expand environment variables "data".
32 Data can be string, list, tuple and dictionary. For collection, all the
33 contained strings will be manipulated (recursively).
34 """
35 import os.path
36 typ = type(data)
37 if typ is str:
38 return os.path.expandvars(data)
39 elif typ in [list, tuple]:
40 collect = []
41 for i in data:
42 collect.append(expandvars(i))
43 return typ(collect)
44 elif typ is dict:
45 collect = {}
46 for k in data:
47 collect[expandvars(k)] = expandvars(data[k])
48 return collect
49 return data
50
51 class Error(RuntimeError):
52 """
53 Error occurred in the configuration process.
54 """
55 pass
56
57 ## Allow references to options as in old style
58 class PropertyReference(object):
59 def __init__(self,propname):
60 self.name = propname
61 def __repr__(self):
62 return "@%s"%self.name
63 def __resolve__(self):
64 # late binding for property references
65 retval = None
66 refname, refprop = self.name.rsplit('.',1)
67 if refname in Configurable.allConfigurables:
68 conf = Configurable.allConfigurables[refname]
69 retval = getattr(conf,refprop)
70 if hasattr(retval,"getFullName"):
71 retval = retval.getFullName()
72 else:
73 raise NameError("name '%s' not found resolving '%s'"%(refname,self))
74 return retval
75 def getFullName(self):
76 """This function allow transparent integration with
77 Configurable.getValuedProperties.
78 """
79 try:
80 return self.__resolve__()
81 except NameError:
82 # ignore the error if we cannot resolve the name yet
83 return self
84 except AttributeError:
85 # ignore the error if we cannot resolve the attribute yet
86 return self
87
88 ### base class for configurable Gaudi algorithms/services/algtools/etc. ======
89 class Configurable( object ):
90 """Base class for Gaudi components that implement the IProperty interface.
91 Provides most of the boilerplate code, but the actual useful classes
92 are its derived ConfigurableAlgorithm, ConfigurableService, and
93 ConfigurableAlgTool."""
94
95 ## for detecting the default name
96 class DefaultName:
97 pass
98
99 propertyNoValue = '<no value>'
100 indentUnit = '| '
101 printHeaderWidth=100
102 printHeaderPre=5
103
104 __metaclass__ = ConfigurableMeta.ConfigurableMeta
105
106 __slots__ = (
107 '__children', # controlled components, e.g. private AlgTools
108 '__tools', # private AlgTools (#PM-->)
109 '_name', # the (unqualified) component name
110 '_inSetDefaults', # currently setting default values
111 '_initok', # used to enforce base class init
112 '_setupok' # for debugging purposes (temporary)
113 )
114
115 allConfigurables = {} # just names would do, but currently refs to the actual
116 configurableServices = {} # just names would do, but currently refs to the actual
117 # configurables is needed for (temporary) backwards
118 # compatibility; will change in the future
119 _configurationLocked = False
120
121 def __new__ ( cls, *args, **kwargs ):
122 """To Gaudi, any object with the same type/name is the same object. Hence,
123 this is mimicked in the configuration: instantiating a new Configurable
124 of a type with the same name will return the same instance."""
125
126 global log
127 # try to get the name of the Configurable (having a name is compulsory)
128 if 'name' in kwargs:
129 # simple keyword (by far the easiest)
130 name = kwargs[ 'name' ]
131 elif 'name' in cls.__init__.func_code.co_varnames:
132 # either positional in args, or default
133 index = list(cls.__init__.func_code.co_varnames).index( 'name' )
134 try:
135 # var names index is offset by one as __init__ is to be called with self
136 name = args[ index - 1 ]
137 except IndexError:
138 # retrieve default value, then
139 name = cls.__init__.func_defaults[ index - (len(args)+1) ]
140 else:
141 # positional index is assumed (will work most of the time)
142 try:
143 name = args[1] # '0' is for self
144 except (IndexError,TypeError):
145 raise TypeError( 'no "name" argument while instantiating "%s"' % cls.__name__ )
146
147 argname = name
148 if name == Configurable.DefaultName :
149 if hasattr(cls, 'DefaultedName' ) :
150 name = cls.DefaultedName
151 else :
152 name = cls.getType()
153 elif not name or type(name) != str:
154 # unnamed, highly specialized user code, etc. ... unacceptable
155 raise TypeError( 'could not retrieve name from %s.__init__ arguments' % cls.__name__ )
156
157 # Handle the case of global tools to prepend ToolSvc in the name.
158 # This is needed for compatibility with old JobOptions files being read
159 if issubclass( cls, ConfigurableAlgTool) and '.' not in name :
160 name = 'ToolSvc.' + name
161
162 # close backdoor access to otherwise private subalgs/tools
163 #PM if 0 <= name.find( '.' ):
164 #PM # temp protection for old style types
165 #PM from OldStyleConfig import GenericConfigurable
166 #PM if not issubclass( cls, GenericConfigurable ): # except raised for new types only
167 #PM raise NameError( '"%s": backdoor access to private configurables not allowed' % name )
168
169 # ordinary recycle case
170 if name in cls.configurables:
171 conf = cls.configurables[ name ]
172 if name != argname: # special case: user derived <-> real ... make same
173 cls.configurables[ conf.getType() ] = conf
174 #---PM: Initialize additional properties
175 for n,v in kwargs.items():
176 if n != "name": # it should not be confused with a normal property
177 setattr(conf, n, v)
178 if not cls._configurationLocked and not "_enabled" in kwargs and isinstance(conf, ConfigurableUser):
179 # Ensure that the ConfigurableUser gets enabled if nothing is
180 # specified in the constructor.
181 setattr(conf, "_enabled", True)
182 return conf
183
184 # a couple of special cases (note that these cases don't mix)
185 spos = name.find( '/' )
186 ti_name = None
187 if spos < 0:
188 ti_name = "%s/%s" % (name,name)
189 if ti_name in cls.configurables:
190 # support for old-style name as type/name lookup where name==type
191 return cls.configurables[ ti_name ]
192
193 i_name = None
194 if spos > 0:
195 i_name = name[:spos]
196 if i_name == name[spos+1:] and i_name in cls.configurables:
197 # this is the opposite of the above special case
198 return cls.configurables[ i_name ]
199
200 # the following is purely for debugging support and should realistically bomb
201 conf = cls.allConfigurables.get( name, None ) or\
202 (spos < 0 and cls.allConfigurables.get( ti_name, None )) or\
203 (spos > 0 and i_name == name[spos+1:] and cls.allConfigurables.get( i_name, None ))
204 if conf: # wrong type used?
205 if conf.__class__ is ConfigurableGeneric :
206 # If the instance found is ConfigurableGeneric then
207 # we create a new one with the proper type and fill with
208 # the contents of the generic one
209 newconf = object.__new__( cls )
210 cls.__init__( newconf, *args, **kwargs )
211 # initialize with the properties of generic configurable
212 # (we map the names of the properties to lowercase versions because
213 # old options are not case sensitive)
214 names = {}
215 for n in newconf.__slots__:
216 names[n.lower()] = n
217 for n in conf._properties:
218 if names[n.lower()] != n:
219 log.warning( "Option '%s' was used for %s, but the correct spelling is '%s'"%(n,name,names[n.lower()]) )
220 setattr(newconf, names[n.lower()], getattr( conf, n ) )
221 for n,v in kwargs.items():
222 setattr(newconf, n, v)
223 cls.configurables[ name ] = newconf
224 cls.allConfigurables[ name ] = newconf
225 return newconf
226 else :
227 # will be an actual error in the future (now only report as such)
228 log.error( 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
229 name, conf.__class__.__name__, cls.__name__, error_explanation )
230 # in the future:
231 # return None # will bomb on use (or go unharmed on non-use)
232 # for now, allow use through allConfigurables lookup
233 #---PM: Initialize additional properties
234 for n,v in kwargs.items():
235 setattr(conf, n, v)
236 return conf
237
238 # still here: create a new instance and initialize it
239 conf = object.__new__(cls)
240 cls.__init__( conf, *args, **kwargs )
241
242 # update normal, per-class cache
243 cls.configurables[ name ] = conf
244
245 for base in cls.__bases__:
246 if base.__name__ == 'ConfigurableService':
247 cls.configurableServices[ name ] = conf
248
249 # update generics super-cache, if needed
250 cls.allConfigurables[ name ] = conf
251 #-->PM#if hasattr( cls, 'getType' ) and name.find('/') < 0:
252 #-->PM# cls.allConfigurables[ cls.getType() + '/' + name ] = conf
253
254 return conf
255
256 def __init__( self, name = DefaultName ):
257 # check class readiness, all required overloads should be there now
258 klass = self.__class__
259
260 # this is an abstract class
261 if klass == Configurable:
262 raise TypeError, "%s is an ABC and can not be instantiated" % str(Configurable)
263
264 # the following methods require overloading
265 #NOT YET meths = { 'getServices' : 1, # retrieve list of services to configure
266 meths = { 'getDlls' : 1, # provide list of Dlls to load
267 'getGaudiType' : 1, # return string describing component class
268 'getHandle' : 1 } # provide access to C++ side component instance
269 # 'getType' : 1 } # return the type of the actual C++ component
270
271 for meth, nArgs in meths.items():
272 try:
273 f = getattr( klass, meth ).im_func
274 except AttributeError:
275 raise NotImplementedError, "%s is missing in class %s" % (meth,str(klass))
276
277 # in addition, verify the number of arguments w/o defaults
278 nargcount = f.func_code.co_argcount
279 ndefaults = f.func_defaults and len(f.func_defaults) or 0
280 if not nargcount - ndefaults <= nArgs <= nargcount:
281 raise TypeError, "%s.%s requires exactly %d arguments" % (klass,meth,nArgs)
282
283 # for using this Configurable as a (Gaudi) sequence
284 self.__children = []
285 self.__tools = {}
286
287 # know who we are
288 if name == Configurable.DefaultName :
289 if hasattr(self.__class__, 'DefaultedName' ) :
290 self._name = self.__class__.DefaultedName
291 else :
292 self._name = self.getType()
293 else :
294 self._name = name
295
296 # set to True when collecting defaults, False otherwise
297 self._inSetDefaults = False
298
299 # for later, in case __init__ itself is overridden
300 self._initok = True
301
302 # for debugging purposes (temporary)
303 self._setupok = False
304
305 # pickle support
306 def __getstate__ (self):
307 dict = {}
308 for name, proxy in self._properties.items():
309 try:
310 dict[ name ] = proxy.__get__( self )
311 except AttributeError:
312 pass
313
314 dict[ '_Configurable__children' ] = self.__children
315 dict[ '_Configurable__tools' ] = self.__tools
316 dict[ '_name' ] = self._name
317 return dict
318
319 def __getnewargs__(self) :
320 return (self._name,)
321
322 def __setstate__ ( self, dict ):
323 self._initok = True
324 for n, v in dict.items():
325 setattr (self, n, v)
326 return
327
328 # to allow a few basic sanity checks, as well as nice syntax
329 def __len__( self ):
330 return len( self.__children )
331
332 def __iter__( self ):
333 return iter( self.__children )
334
335 # ownership rules of self through copying
336 def __deepcopy__( self, memo ):
337 newconf = object.__new__( self.__class__ )
338 self.__class__.__init__( newconf, self.getName() )
339
340 for proxy in self._properties.values():
341 try:
342 proxy.__set__( newconf, proxy.__get__( self ) )
343 except AttributeError:
344 pass # means property was not set for self
345
346 for c in self.__children:
347 newconf += c # processes proper copy semantics
348
349 return newconf
350
351 # hierarchy building, and ownership rules of children
352 def __iadd__( self, configs, descr = None ):
353 if not type(configs) in (list,tuple):
354 configs = ( configs, )
355
356 joname = self.getJobOptName()
357
358 for cfg in configs:
359 # prevent type mismatches
360 if not isinstance( cfg, Configurable ):
361 raise TypeError( "'%s' is not a Configurable" % str(cfg) )
362
363 cc = self.copyChildAndSetParent( cfg, joname )
364
365 # filters dupes; usually "ok" (backdoor should catch them)
366 ccjo = cc.getJobOptName()
367 for c in self.__children:
368 if c.getJobOptName() == ccjo:
369 log.error( 'attempt to add a duplicate ... dupe ignored%s', error_explanation )
370 break
371 else:
372 self.__children.append( cc )
373
374 try:
375 if descr: # support for tool properties
376 descr.__set__( self, cc )
377 else:
378 setattr( self, cc.getName(), cc )
379 except AttributeError:
380 pass # to allow free addition of tools/subalgorithms
381
382 return self
383
384 def __getattr__( self, attr ): # until ToolProperties exist ...
385
386 if attr in self.__tools : return self.__tools[attr]
387
388 if attr in self._properties:
389 if isinstance(self._properties[attr].__get__( self ), DataObjectHandleBase):
390 return self._properties[attr].__get__( self )
391
392 for c in self.__children:
393 if c.getName() == attr:
394 return c
395
396 raise AttributeError( "'%s' object has no attribute '%s'" % (self.__class__,attr) )
397
398 def __setattr__( self, name, value ) :
399 if self._configurationLocked:
400 raise RuntimeError("%s: Configuration cannot be modified after the ApplicationMgr has been started."%self.name())
401 try :
402 super( Configurable, self ).__setattr__( name, value )
403 except AttributeError:
404 raise AttributeError( "Configurable '%s' does not have property '%s'."
405 % ( self.__class__.__name__, name) )
406
407 def __delattr__( self, attr ):
408 # remove as property, otherwise try as child
409 try:
410 # remove history etc., then reset to default (in case set before)
411 prop = self._properties[ attr ]
412 prop.__delete__( self )
413 prop.__set__( self, prop.default )
414 return # reaches here? was property: done now
415 except KeyError:
416 pass
417 # otherwise, remove the private tool
418 if attr in self.__tools :
419 del self.__tools[attr]
420
421 # otherwise, remove child, if one is so named
422 for c in self.__children:
423 if c.getName() == attr:
424 self.__children.remove( c )
425
426 # potentially, there are left over caches (certain user derived classes)
427 try:
428 del self.__dict__[ attr ]
429 except (AttributeError,KeyError):
430 pass
431
432 def __nonzero__(self):
433 return True
434
435
436 def remove( self, items ):
437 if type(items) != list and type(items) != tuple:
438 items = [ items ]
439
440 self.__children = [ e for e in self.__children if not e in items ]
441
442 def removeAll( self ):
443 self.remove( self.__children )
444
445 # called by __iadd__; determines child copy semantics
446 def copyChild( self, child ):
447 return copy.deepcopy( child )
448
449 def setParent( self, parentName ):
450 pass
451
452 def getParent( self ):
453 return ""
454
455 def hasParent( self, parent ):
456 return False
457
458 def copyChildAndSetParent(self,cfg,parent):
459 cc = self.copyChild( cfg )
460
461 if hasattr( cc, 'setParent' ) and parent:
462 try:
463 cc.setParent( parent )
464 except RuntimeError, e:
465 # temporary backdoor resolution for compatibility
466 log.error( str(e) + '%s', error_explanation )
467 ccbd = cc.configurables[ cc.getJobOptName() ]
468
469 # merge properties, new over pre-existing
470 for proxy in self._properties.values():
471 if proxy.history.has_key( cc ):
472 proxy.__set__( ccbd, proxy.__get__( cc ) )
473
474 # consolidate
475 cc = ccbd
476 return cc
477
478 def getChildren( self ):
479 return self.__children[:] # read only
480
481 def getTools( self ):
482 return self.__tools.values() # read only
483
484 def children( self ):
485 log.error( "children() is deprecated, use getChildren() instead for consistency" )
486 log.error( "getChildren() returns a copy; to add a child, use 'parent += child'%s",
487 error_explanation )
488 return self.__children # by ref, for compatibility
489
490 def getAllChildren( self ):
491 """Get all (private) configurable children, both explicit ones (added with +=)
492 and the ones in the private GaudiHandle properties"""
493 childs = []
494 # add private configurable properties (also inside handles)
495 for proxy in self._properties.values():
496 try:
497 c = proxy.__get__( self )
498 except AttributeError:
499 pass
500 else:
501 if isinstance(c,Configurable) and not c.isPublic():
502 childs.append(c)
503 elif isinstance(c,GaudiHandle):
504 try:
505 conf = c.configurable
506 except AttributeError:
507 pass
508 else:
509 if not conf.isPublic():
510 childs.append(conf)
511 elif isinstance(c,GaudiHandleArray):
512 # only setup private arrays
513 if not c.isPublic():
514 for ci in c:
515 if isinstance(ci,Configurable):
516 childs.append(ci)
517 else:
518 try:
519 conf = ci.configurable
520 except AttributeError:
521 pass
522 else:
523 childs.append(conf)
524
525 # add explicit children
526 childs += self.__children
527 return childs
528
529 def getSequence( self ):
530 elems = []
531 for c in self.__children:
532 elems.append( c.getFullName() )
533 return elems
534
535 def setup( self ):
536 # make sure base class init has been called
537 if not hasattr(self,'_initok') or not self._initok:
538 # could check more, but this is the only explanation
539 raise TypeError, \
540 "Configurable.__init__ not called in %s override" % self.__class__.__name__
541
542 # log.debug("calling setup() on " + self.getFullJobOptName())
543
544 # setup self: this collects all values on the python side
545 self.__setupServices()
546 self.__setupDlls()
547 self.__setupDefaults()
548
549 # setup children
550 for c in self.getAllChildren():
551 c.setup()
552
553 # now get handle to work with for moving properties into the catalogue
554 handle = self.getHandle()
555 if not handle:
556 log.debug( 'no handle for %s: not transporting properties', self._name )
557 return # allowed, done early
558
559 # pass final set of properties on to handle on the C++ side or JobOptSvc
560 for name in self._properties.keys():
561 if hasattr( self, name ): # means property has python-side value/default
562 setattr( handle, name, getattr(self,name) )
563
564 # for debugging purposes
565 self._setupok = True
566
567 def getProperties( self ):
568 props = {}
569 for name, proxy in self._properties.items():
570 try:
571 props[ name ] = proxy.__get__( self )
572 except AttributeError:
573 props[ name ] = Configurable.propertyNoValue
574
575 return props
576
577 def getPropertiesWithDescription( self ):
578 """Get all properties with their description string as { name : (value, desc) }."""
579 props = {}
580 for name, proxy in self._properties.items():
581 try:
582 props[ name ] = ( proxy.__get__( self ), proxy.__doc__)
583 except AttributeError:
584 props[ name ] = ( Configurable.propertyNoValue, proxy.__doc__)
585 return props
586
587 def getValuedProperties( self ):
588 props = {}
589 for name, proxy in self._properties.items():
590 if self.isPropertySet(name):
591 value = proxy.__get__( self )
592 if hasattr(value, 'getFullName') :
593 value = value.getFullName()
594 elif type(value) in [list, tuple]:
595 new_value = []
596 for i in value:
597 if hasattr(i, 'getFullName'):
598 new_value.append(i.getFullName())
599 else:
600 new_value.append(i)
601 value = type(value)(new_value)
602 elif type(value) is dict:
603 new_value = {}
604 for i in value:
605 if hasattr(value[i], 'getFullName'):
606 new_value[i] = value[i].getFullName()
607 else:
608 new_value[i] = value[i]
609 value = new_value
610 props[ name ] = value
611
612 return props
613
614 def properties( self ):
615 return self.getProperties() # compatibility
616
617 @classmethod
618 def getDefaultProperties( cls ):
619 class collector:
620 pass
621
622 # user provided defaults
623 c = collector()
624 cls.setDefaults( c )
625
626 # defaults from C++
627 for k,v in cls._properties.items():
628 if not k in c.__dict__ and hasattr( v, 'default' ):
629 c.__dict__[ k ] = v.default
630
631 return c.__dict__
632
633 @classmethod
634 def getDefaultProperty( cls, name ):
635 class collector:
636 pass
637
638 # user provided defaults
639 c = collector()
640 cls.setDefaults( c )
641
642 if name in c.__dict__:
643 return c.__dict__[ name ]
644
645 # defaults from C++
646 try:
647 v = cls._properties[name]
648 if hasattr( v, 'default' ):
649 return v.default
650 except KeyError:
651 pass
652
653 return None
654
655 def getProp(self, name):
656 """Returns the value of the given property.
657 """
658 if hasattr(self, name):
659 return getattr(self, name)
660 else:
661 return self.getDefaultProperties()[name]
662
663 def setProp(self, name, value):
664 """Set the value of a given property
665 """
666 return setattr(self, name, value)
667
668 def isPropertySet(self, name):
669 """Tell if the property 'name' has been set or not.
670
671 Because of a problem with list and dictionary properties, in those cases
672 if the value is equal to the default, the property is considered as not
673 set.
674 """
675 if not hasattr(self, name):
676 return False
677 else:
678 default = self.getDefaultProperty(name)
679 if isinstance(default, (list, dict)):
680 value = getattr(self, name)
681 return value != default
682 return True
683
684 def getType( cls ):
685 return cls.__name__
686
687 def getName( self ):
688 return self._name
689
690 def name( self ):
691 return self.getName()
692
693 def getJobOptName( self ): # full hierachical name
694 return self.getName()
695
696 def isPublic( self ):
697 return True
698
699 # for a couple of existing uses out there
700 def jobOptName( self ):
701 log.error( "jobOptName() is deprecated, use getJobOptName() instead for consistency%s",
702 error_explanation )
703 return self.getJobOptName() # compatibility
704
705 def getFullName( self ) :
706 return str( self.getType() + '/' + self.getName() )
707
708 def getFullJobOptName( self ):
709 return "%s/%s" % (self.getType(),self.getJobOptName() or self.getName())
710
711 def getPrintTitle(self):
712 return self.getGaudiType() + ' ' + self.getTitleName()
713
714 def getTitleName( self ):
715 if log.isEnabledFor( logging.DEBUG ):
716 return self.getFullJobOptName()
717 else:
718 return self.getFullName()
719
720 def setDefaults( cls, handle ):
721 pass
722
723 def clone( self, name = None, **kwargs ) :
724 if not name :
725 if hasattr(self, 'DefaultedName' ) : name = self.DefaultedName
726 else : name = self.getType()
727
728 newconf = Configurable.__new__( self.__class__, name )
729 self.__class__.__init__( newconf, name )
730
731 for proxy in self._properties.values():
732 try :
733 value = proxy.__get__( self )
734 if type(value) in [ str, list, dict, tuple ]:
735 # clone the values of the properties for basic types
736 value = type(value)(value)
737 proxy.__set__( newconf, value )
738 except AttributeError:
739 pass
740
741 for c in self.__children:
742 newconf += c # processes proper copy semantics
743
744 for n , t in self.__tools.items():
745 newconf.addTool(t, n)
746
747 for name, value in kwargs.items():
748 setattr(newconf, name, value)
749
750 return newconf
751
752 def splitName( self ) :
753 fullname = self.getName()
754 dot = fullname.find('.')
755 if dot != -1 :
756 parentname = fullname[:dot]
757 longname = fullname[dot+1:]
758 else :
759 parentname = ''
760 longname = fullname
761 dot = longname.find('.')
762 if dot != -1 :
763 name = longname[:dot]
764 else :
765 name = longname
766 return parentname, name, longname
767
768 def addTool( self, tool, name = None ) :
769 if isclass(tool) and issubclass(tool, ConfigurableAlgTool):
770 if name is None:
771 name = tool.__name__
772 priv_tool = tool( self.getName()+ '.' + name )
773 elif isinstance(tool, ConfigurableAlgTool):
774 if name is None:
775 name = tool.splitName()[1]
776 priv_tool = tool.clone( self.getName()+ '.' + name )
777 else:
778 if isclass(tool):
779 classname = tool.__name__
780 else:
781 classname = type(tool).__name__
782 raise TypeError, "addTool requires AlgTool configurable. Got %s type" % classname
783 self.__tools[name] = priv_tool
784 if name in self.__slots__:
785 # this is to avoid that the property hides the tool
786 setattr(self,name,self.__tools[name])
787 return self.__tools[name]
788
789 def _isInSetDefaults( self ):
790 return self._inSetDefaults
791
792 def __setupServices( self ):
793 #svcs = self.getServices()
794 #if not svcs:
795 svcs = []
796 #elif type(svcs) == types.StringType:
797 # svcs = [ svcs ]
798
799 import __main__
800 for svc in svcs:
801 handle = __main__.Service( svc )
802 # services should be configurables as well, but aren't for now
803 # handle.setup()
804
805 # allow Configurable to make some changes
806 if hasattr( self, 'configure' + svc ):
807 eval( 'self.configure' + svc + '( handle )' )
808
809 def __setupDlls( self ):
810 dlls = self.getDlls()
811 if not dlls:
812 dlls = []
813 elif type(dlls) == types.StringType:
814 dlls = [ dlls ]
815
816 from __main__ import theApp
817 dlls = filter( lambda d: d not in theApp.Dlls, dlls )
818 if dlls: theApp.Dlls += dlls
819
820 def __setupDefaults( self ):
821 # set handle defaults flags to inform __setattr__ that it is being
822 # called during setDefaults of the concrete Configurable
823 self._inSetDefaults = True
824 self.setDefaults( self )
825 self._inSetDefaults = False
826
827 @staticmethod
828 def _printHeader( indentStr, title ):
829 preLen = Configurable.printHeaderPre
830 postLen = Configurable.printHeaderWidth - preLen - 3 - len(title)# - len(indentStr)
831 postLen = max(preLen,postLen)
832 return indentStr + '/%s %s %s' % (preLen*'*',title,postLen*'*')
833
834 @staticmethod
835 def _printFooter( indentStr, title ):
836 preLen = Configurable.printHeaderPre
837 postLen = Configurable.printHeaderWidth - preLen - 12 - len(title)# - len(indentStr)
838 postLen = max(preLen,postLen)
839 return indentStr + '\\%s (End of %s) %s' % (preLen*'-',title,postLen*'-')
840
841 def __repr__( self ):
842 return '<%s at %s>' % (self.getFullJobOptName(),hex(id(self)))
843
844 def __str__( self, indent = 0, headerLastIndentUnit=indentUnit ):
845 global log # to print some info depending on output level
846 indentStr = indent*Configurable.indentUnit
847 # print header
848 title = self.getPrintTitle()
849 # print line to easily see start-of-configurable
850 if indent > 0:
851 headerIndent = (indent-1)*Configurable.indentUnit + headerLastIndentUnit
852 else:
853 headerIndent = ''
854 rep = Configurable._printHeader( headerIndent, title )
855 rep += os.linesep
856 # print own properties
857 props = self.getProperties()
858 defs = self.getDefaultProperties()
859 if not props:
860 rep += indentStr + '|-<no properties>' + os.linesep
861 else:
862 # get property name with
863 nameWidth = 0
864 for p in props.keys():
865 nameWidth=max(nameWidth,len(p))
866 for p, v in props.items():
867 # start with indent and property name
868 prefix = indentStr + '|-%-*s' % (nameWidth,p)
869 # add memory address for debugging (not for defaults)
870 if log.isEnabledFor( logging.DEBUG ):
871 if v != Configurable.propertyNoValue:
872 address = ' @%11s' % hex(id(v))
873 else:
874 address = 13*' '
875 prefix += address
876 # add value and default
877 default = defs.get(p)
878 if v == Configurable.propertyNoValue:
879 # show default value as value, and no extra 'default'
880 strVal = repr(default)
881 strDef = None
882 else:
883 # convert configurable to handle
884 if hasattr(v,"getGaudiHandle"):
885 vv = v.getGaudiHandle()
886 else:
887 vv = v
888 if isinstance(vv,GaudiHandle) or isinstance(vv,GaudiHandleArray):
889 strVal = repr(vv)
890 if hasattr(default,"toStringProperty"): # the default may not be a GaudiHandle (?)
891 strDef = repr(default.toStringProperty())
892 else:
893 strDef = repr(default)
894 if strDef == repr(vv.toStringProperty()):
895 strDef = None
896 else:
897 strVal = repr(vv)
898 strDef = repr(default)
899 # add the value
900 line = prefix + ' = ' + strVal
901 # add default if present
902 if strDef is not None:
903 # put default on new line if too big
904 if len(line) + len(strDef) > Configurable.printHeaderWidth:
905 line += os.linesep + indentStr + '| ' + (len(prefix)-len(indentStr)-3)*' '
906 line += ' (default: %s)' % (strDef,)
907 # add the line to the total string
908 rep += line + os.linesep
909 # print out full private configurables
910 ## if isinstance(v,Configurable) and not v.isPublic():
911 ## rep += v.__str__( indent + 1 ) + os.linesep
912 ## elif isinstance(v,GaudiHandleArray):
913 ## for vi in v:
914 ## if isinstance(vi,Configurable) and not vi.isPublic():
915 ## rep += vi.__str__( indent + 1 ) + os.linesep
916
917 # print configurables + their properties, or loop over sequence
918 ## for cfg in self.__children:
919 for cfg in self.getAllChildren():
920 rep += cfg.__str__( indent + 1, '|=' ) + os.linesep
921
922 # print line to easily see end-of-configurable. Note: No linesep!
923 rep += Configurable._printFooter( indentStr, title )
924 return rep
925
926 def isApplicable(self):
927 '''
928 Return True is the instance can be "applied".
929 Always False for plain Configurable instances
930 (i.e. not ConfigurableUser).
931 '''
932 return False
933
934 ### classes for generic Gaudi component ===========
935 class DummyDescriptor( object ):
936 def __init__( self, name ):
937 self.__name__ = name # conventional
938
939 def __get__( self, obj, type = None ):
940 return getattr( obj, self.__name__ )
941
942 def __set__( self, obj, value ):
943 object.__setattr__( obj, self.__name__, value )
944
945 class ConfigurableGeneric( Configurable ):
946 #__slots__ = { }
947
948 def __init__( self, name = Configurable.DefaultName ):
949 Configurable.__init__( self, name )
950 self._name = name
951 self._properties = {}
952
953 def __deepcopy__( self, memo ):
954 return self # algorithms are always shared
955
956 def getGaudiType( self ): return 'GenericComponent'
957 def getDlls( self ) : pass
958 def getHandle( self ) : pass
959
960 def __setattr__( self, name, value ):
961 # filter private (user) variables
962 if name[0] == '_':
963 super( ConfigurableGeneric, self ).__setattr__( name, value )
964 return
965
966 # filter configurable types
967 if isinstance( value, Configurable ):
968 self.__dict__[ name ] = value
969 return
970
971 # assume all the rest are properties
972 if not name in self._properties:
973 self._properties[ name ] = PropertyProxy( DummyDescriptor( name ) )
974 self._properties[ name ].__set__( self, value )
975
976 def getJobOptName( self ): return None
977
978
979 ### base classes for individual Gaudi algorithms/services/algtools ===========
980 class ConfigurableAlgorithm( Configurable ):
981 __slots__ = { '_jobOptName' : 0, 'OutputLevel' : 0, \
982 'Enable' : 1, 'ErrorMax' : 1, 'ErrorCount' : 0, 'AuditAlgorithms' : 0, \
983 'AuditInitialize' : 0, 'AuditReinitialize' : 0, 'AuditExecute' : 0, \
984 'AuditFinalize' : 0, 'AuditBeginRun' : 0, 'AuditEndRun' : 0 }
985
986 def __init__( self, name = Configurable.DefaultName ):
987 super( ConfigurableAlgorithm, self ).__init__( name )
988 name = self.getName()
989 self._jobOptName = name[ name.find('/')+1 : ] # strips class
990
991 def __deepcopy__( self, memo ):
992 return self # algorithms are always shared
993
994 def getHandle( self ):
995 return iAlgorithm( self.getJobOptName() )
996
997 def getGaudiType( self ):
998 return 'Algorithm'
999
1000 def getJobOptName( self ):
1001 return self._jobOptName
1002
1003
1004 class ConfigurableService( Configurable ):
1005 __slots__ = { 'OutputLevel' : 0, \
1006 'AuditServices' : 0, 'AuditInitialize' : 0, 'AuditFinalize' : 0 }
1007
1008 def __deepcopy__( self, memo ):
1009 return self # services are always shared
1010
1011 def copyChild( self, child ):
1012 return child # full sharing
1013
1014 def getHandle( self ):
1015 return iService( self._name )
1016
1017 def getGaudiType( self ):
1018 return 'Service'
1019
1020 def getGaudiHandle( self ):
1021 return ServiceHandle( self.toStringProperty() )
1022
1023 def toStringProperty( self ):
1024 # called on conversion to a string property for the jocat
1025 return self.getName()
1026
1027
1028 class ConfigurableAlgTool( Configurable ):
1029 __slots__ = { '_jobOptName' : '', 'OutputLevel' : 0, \
1030 'AuditTools' : 0, 'AuditInitialize' : 0, 'AuditFinalize' : 0 }
1031
1032 def __init__( self, name = Configurable.DefaultName ):
1033 super( ConfigurableAlgTool, self ).__init__( name )
1034 if '.' not in self._name:
1035 # Public tools must have ToolSvc as parent
1036 self._name = "ToolSvc." + self._name
1037 name = self.getName()
1038 name = name[ name.find('/')+1 : ] # strips class, if any
1039 self._jobOptName = name
1040
1041 def getHandle( self ):
1042 # iAlgTool isn't useful, unless one knows for sure that the tool exists
1043 return iProperty( self.getJobOptName() )
1044
1045 def getGaudiType( self ):
1046 return 'AlgTool'
1047
1048 def getGaudiHandle( self ):
1049 if self.isPublic():
1050 return PublicToolHandle( self.toStringProperty() )
1051 else:
1052 return PrivateToolHandle( self.toStringProperty() )
1053
1054 def getPrintTitle(self):
1055 if self.isPublic():
1056 pop = 'Public '
1057 else:
1058 pop = 'Private '
1059 return pop + Configurable.getPrintTitle(self)
1060
1061 def setParent( self, parentName ):
1062 # print "ConfigurableAlgTool.setParent(%s@%x,%r)" % (self.getName(),id(self),parentName)
1063 # print "Calling stack:"
1064 # import traceback
1065 # traceback.print_stack()
1066 # propagate parent to AlgTools in children
1067 for c in self.getAllChildren():
1068 if isinstance(c,ConfigurableAlgTool): c.setParent( parentName )
1069
1070 # update my own parent
1071 name = self.getName()
1072 name = name[name.rfind('.')+1:] # Name of the instance
1073 self._jobOptName = self._name = parentName + '.' + name
1074
1075 def getParent( self ):
1076 dot = self._jobOptName.rfind('.')
1077 if dot != -1:
1078 return self._jobOptName[:dot]
1079 else:
1080 return ""
1081
1082 def hasParent( self, parent ):
1083 return self._jobOptName.startswith( parent + '.' )
1084
1085 def getJobOptName( self ):
1086 return self._jobOptName
1087
1088 def isPublic( self ):
1089 return self.isInToolSvc()
1090
1091 def isInToolSvc( self ):
1092 return self._jobOptName.startswith('ToolSvc.')
1093
1094 def toStringProperty( self ):
1095 # called on conversion to a string property for the jocat
1096 return self.getFullName()
1097
1098 def getFullName( self ) :
1099 # for Tools, the "full name" means "Type/LocalName",
1100 # without the names of the parents
1101 name = self.getName()
1102 # strip off everything before the last '.'
1103 name = name[name.rfind('.')+1:]
1104 return str( self.getType() + '/' + name )
1105
1106
1107 ### FIXME: this is just a placeholder, waiting for a real implementation
1108 ### It is sufficient to get us going... (and import a PkgConf which
1109 ### happens to contain an Auditor...)
1110 class ConfigurableAuditor( Configurable ):
1111 __slots__ = { '_jobOptName' : 0, 'OutputLevel' : 0, \
1112 'Enable' : 1 }
1113
1114 def __init__( self, name = Configurable.DefaultName ):
1115 super( ConfigurableAuditor, self ).__init__( name )
1116 name = self.getName()
1117 name = name[ name.find('/')+1 : ] # strips class, if any
1118 self._jobOptName = name
1119
1120 def getHandle( self ):
1121 # iAlgTool isn't useful, unless one knows for sure that the tool exists
1122 return iProperty( self.getJobOptName() )
1123
1124 def getGaudiType( self ):
1125 return 'Auditor'
1126
1127 def getJobOptName( self ):
1128 return self._jobOptName
1129
1130 def toStringProperty( self ):
1131 # called on conversion to a string property for the jocat
1132 return self.getType() + '/' + self.getName()
1133
1134 class ConfigurableUser( Configurable ):
1135 __slots__ = { "__users__": [],
1136 "__used_instances__": [],
1137 "_enabled": True,
1138 "_applied": False }
1139 ## list of ConfigurableUser classes this one is going to modify in the
1140 # __apply_configuration__ method.
1141 # The list may contain class objects, strings representing class objects or
1142 # tuples with the class object (or a string) as first element and the instance
1143 # name as second element.
1144 # If the instance name is None or not present, the function _instanceName()
1145 # is used to determine the name of the instance (the default implementation
1146 # returns "<this name>_<other name>".
1147 __used_configurables__ = []
1148 ## list of ConfigurableUser classes this one is going to query in the
1149 # __apply_configuration__ method
1150 __queried_configurables__ = []
1151 def __init__( self, name = Configurable.DefaultName, _enabled = True, **kwargs ):
1152 super( ConfigurableUser, self ).__init__( name )
1153 for n, v in kwargs.items():
1154 setattr(self, n, v)
1155 self._enabled = _enabled
1156 self.__users__ = []
1157 self._applied = False
1158
1159 # Needed to retrieve the actual class if the declaration in __used_configurables__
1160 # and __queried_configurables__ is done with strings.
1161 from GaudiKernel.ConfigurableDb import getConfigurable as confDbGetConfigurable
1162
1163 # Set the list of users of the used configurables
1164 #
1165 self.__used_instances__ = []
1166 for used in self.__used_configurables__:
1167 # By default we want to use the default name of the instances
1168 # for the used configurables
1169 used_name = Configurable.DefaultName
1170 # If the entry in the list is a tuple, we need a named instance
1171 if type(used) is tuple:
1172 used, used_name = used # we re-set used to re-use the code below
1173 if not used_name:
1174 used_name = self._instanceName(used)
1175 # Check is 'used' is a string or not
1176 if type(used) is str:
1177 used_class = confDbGetConfigurable(used)
1178 else:
1179 used_class = used
1180 # Instantiate the configurable that we are going to use
1181 try:
1182 inst = used_class(name = used_name, _enabled = False)
1183 except AttributeError:
1184 # This cover the case where the used configurable is not a
1185 # ConfigurableUser instance, i.e. id doesn't have the attribute
1186 # '_enabled'.
1187 inst = used_class(name = used_name)
1188 self.__addActiveUseOf(inst)
1189 for queried in self.__queried_configurables__:
1190 try:
1191 if type(queried) is str:
1192 queried = confDbGetConfigurable(used)
1193 inst = queried(_enabled = False)
1194 except AttributeError:
1195 inst = queried()
1196 self.__addPassiveUseOf(inst)
1197 def __addActiveUseOf(self, other):
1198 """
1199 Declare that we are going to modify the Configurable 'other' in our
1200 __apply_configuration__.
1201 """
1202 self.__used_instances__.append(other)
1203 if hasattr(other, "__users__"): # allow usage of plain Configurables
1204 other.__users__.append(self)
1205 def __addPassiveUseOf(self, other):
1206 """
1207 Declare that we are going to retrieve property values from the
1208 ConfigurableUser 'other' in our __apply_configuration__.
1209 """
1210 if not isinstance(other, ConfigurableUser):
1211 raise Error("'%s': Cannot make passive use of '%s', it is not a ConfigurableUser" % (self.name(), other.name()))
1212 other.__addActiveUseOf(self)
1213 def getGaudiType( self ):
1214 return 'User'
1215 def getDlls( self ):
1216 return None
1217 def getHandle( self ):
1218 return None
1219
1220 def __detach_used__(self):
1221 """
1222 Remove this ConfigurableUser instance from the users list of the used
1223 instances.
1224 """
1225 for used in self.__used_instances__:
1226 if hasattr(used, "__users__"): # allow usage of plain Configurables
1227 used.__users__.remove(self)
1228
1229 def propagateProperty(self, name, others = None, force = True):
1230 """
1231 Propagate the property 'name' (if set) to other configurables (if possible).
1232 'others' can be:
1233 None:
1234 propagate to all the entries in __used_configurables__
1235 a configurable instance:
1236 propagate only to it
1237 list of configurable instances:
1238 propagate to all of them.
1239
1240
1241 The logic is:
1242 - if the local property is set, the other property will be overwritten
1243 - local property not set and other set => keep other
1244 - local property not set and other not set => overwrite the default for
1245 ConfigurableUser instances and set the property for Configurables
1246 """
1247 # transform 'others' to a list of configurable instances
1248 if others is None:
1249 others = self.__used_instances__
1250 elif type(others) not in [ list, tuple ] :
1251 others = [ others ]
1252 # these can be computed before the loop
1253 local_is_set = self.isPropertySet(name)
1254 value = self.getProp(name)
1255 # loop over the others that do have 'name' in their slots
1256 for other in [ o for o in others if name in o.__slots__ ]:
1257 # If self property is set, use it
1258 if local_is_set:
1259 if other.isPropertySet(name):
1260 log.warning("Property '%(prop)s' is set in both '%(self)s' and '%(other)s', using '%(self)s.%(prop)s'"%
1261 { "self": self.name(),
1262 "other": other.name(),
1263 "prop": name } )
1264 other.setProp(name, value)
1265 # If not, and other property also not set, propagate the default
1266 elif not other.isPropertySet(name):
1267 if isinstance(other,ConfigurableUser):
1268 otherType = type(other._properties[name].getDefault())
1269 other._properties[name].setDefault(value)
1270 if otherType in [list, dict]:
1271 # Special case for list and dictionaries:
1272 # also set the property to the same value of the default (copy)
1273 other.setProp(name, otherType(value))
1274 else:
1275 other.setProp(name, value)
1276 # If not set and other set, do nothing
1277
1278 def propagateProperties(self, names = None, others = None, force = True):
1279 """
1280 Call propagateProperty for each property listed in 'names'.
1281 If 'names' is None, all the properties are propagated.
1282 """
1283 if names is None:
1284 # use all the non-private slots
1285 names = [ p for p in self.__slots__ if not p.startswith("_") ]
1286 for n in names:
1287 self.propagateProperty(n, others, force)
1288
1289 def __apply_configuration__(self):
1290 """
1291 Function to be overridden to convert the high level configuration into a
1292 low level one.
1293 The default implementation calls applyConf, which is the method defined
1294 in some ConfigurableUser implementations.
1295 """
1296 return self.applyConf()
1297
1298 def applyConf( self ):
1299 """
1300 Function to be overridden to convert the high level configuration into a
1301 low level one.
1302 """
1303 pass
1304
1305 def _instanceName(self, cls):
1306 """
1307 Function used to define the name of the private instance of a given class
1308 name.
1309 This method is used when the __used_configurables_property__ declares the
1310 need of a private used configurable without specifying the name.
1311 """
1312 if type(cls) is str:
1313 clName = cls
1314 else:
1315 clName = cls.__name__
1316 return "%s_%s" % (self.name(), clName)
1317
1318 def getUsedInstance(self, name):
1319 """
1320 Return the used instance with a given name.
1321 """
1322 for i in self.__used_instances__:
1323 if i.name() == name:
1324 if hasattr(i, "_enabled"):
1325 # ensure that the instances retrieved through the method are
1326 # enabled
1327 i._enabled = True
1328 return i
1329 raise KeyError(name)
1330
1331 def isApplicable(self):
1332 '''
1333 Return True is the instance can be "applied".
1334 '''
1335 return (not self.__users__) and (not self._applied)
1336
1337
1338 # list of callables to be called after all the __apply_configuration__ are called.
1339 postConfigActions = []
1340 def appendPostConfigAction(function):
1341 """
1342 Add a new callable ('function') to the list of post-configuration actions.
1343 If the callable is already in the list, it is moved to the end of the list.
1344 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1345 """
1346 try:
1347 postConfigActions.remove(function)
1348 except:
1349 pass
1350 postConfigActions.append(function)
1351 def removePostConfigAction(function):
1352 """
1353 Remove a callable from the list of post-config actions.
1354 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1355 """
1356 postConfigActions.remove(function)
1357
1358 _appliedConfigurableUsers_ = False
1359 def applyConfigurableUsers():
1360 """
1361 Call the apply method of all the ConfigurableUser instances respecting the
1362 dependencies. First the C.U.s that are not used by anybody, then the used
1363 ones, when they are not used anymore.
1364 """
1365 # Avoid double calls
1366 global _appliedConfigurableUsers_, postConfigActions
1367 if _appliedConfigurableUsers_:
1368 return
1369 _appliedConfigurableUsers_ = True
1370
1371 def applicableConfUsers():
1372 '''
1373 Generator returning all the configurables that can be applied in the
1374 order in which they can be applied.
1375 '''
1376 # This is tricky...
1377 # We keep on looking for the first configurable that can be applied.
1378 # When we cannot find any, 'next()' raises a StopIteration that is
1379 # propagated outside of the infinite loop and the function, then handled
1380 # correctly from outside (it is the exception that is raised when you
1381 # exit from a generator).
1382 # Checking every time the full list is inefficient, but it is the
1383 # easiest way to fix bug #103803.
1384 # <https://savannah.cern.ch/bugs/?103803>
1385 while True:
1386 yield (c for c in Configurable.allConfigurables.values()
1387 if c.isApplicable()).next()
1388
1389 debugApplyOrder = 'GAUDI_DUBUG_CONF_USER' in os.environ
1390 for c in applicableConfUsers():
1391 if c._enabled:
1392 log.info("applying configuration of %s", c.name())
1393 if debugApplyOrder:
1394 sys.stderr.write('applying %r' % c)
1395 c.__apply_configuration__()
1396 log.info(c)
1397 else:
1398 log.info("skipping configuration of %s", c.name())
1399 c._applied = True # flag the instance as already applied
1400 if hasattr(c, "__detach_used__"):
1401 # tells the used configurables that they are not needed anymore
1402 c.__detach_used__()
1403
1404 # check for dependency loops
1405 leftConfUsers = [c for c in Configurable.allConfigurables.values()
1406 if hasattr(c, '__apply_configuration__') and
1407 c._enabled and not c._applied]
1408 # if an enabled configurable has not been applied, there must be a dependency loop
1409 if leftConfUsers:
1410 raise Error("Detected loop in the ConfigurableUser"
1411 " dependencies: %r" % [ c.name()
1412 for c in leftConfUsers ])
1413 # ensure that all the Handles have been triggered
1414 known = set()
1415 unknown = set(Configurable.allConfigurables)
1416 while unknown:
1417 for k in unknown:
1418 if not known: # do not print during the first iteration
1419 log.debug('new configurable created automatically: %s', k)
1420 # this trigger the instantiation from handles
1421 Configurable.allConfigurables[k].properties()
1422 known.add(k)
1423 unknown -= known
1424 # Call post-config actions
1425 for action in postConfigActions:
1426 action()
1427
1428 def applyConfigurableUsers_old():
1429 """
1430 Obsolete (buggy) implementation of applyConfigurableUsers(), kept to provide
1431 backward compatibility for configurations that where relying (implicitly) on
1432 bug #103803, or on a specific (non guaranteed) order of execution.
1433
1434 @see applyConfigurableUsers()
1435 """
1436 # Avoid double calls
1437 global _appliedConfigurableUsers_, postConfigActions
1438 if _appliedConfigurableUsers_:
1439 return
1440 _appliedConfigurableUsers_ = True
1441
1442 debugApplyOrder = 'GAUDI_DUBUG_CONF_USER' in os.environ
1443 confUsers = [ c
1444 for c in Configurable.allConfigurables.values()
1445 if hasattr(c,"__apply_configuration__") ]
1446 applied = True # needed to detect dependency loops
1447 while applied and confUsers:
1448 newConfUsers = [] # list of conf users that cannot be applied yet
1449 applied = False
1450 for c in confUsers:
1451 if hasattr(c,"__users__") and c.__users__:
1452 newConfUsers.append(c) # cannot use this one yet
1453 else: # it does not have users or the list is empty
1454 applied = True
1455 # the ConfigurableUser is enabled if it doesn't have an _enabled
1456 # property or its value is True
1457 enabled = (not hasattr(c, "_enabled")) or c._enabled
1458 if enabled:
1459 log.info("applying configuration of %s", c.name())
1460 if debugApplyOrder:
1461 sys.stderr.write('applying %r' % c)
1462 c.__apply_configuration__()
1463 log.info(c)
1464 else:
1465 log.info("skipping configuration of %s", c.name())
1466 if hasattr(c, "__detach_used__"):
1467 # tells the used configurables that they are not needed anymore
1468 c.__detach_used__()
1469 confUsers = newConfUsers # list of C.U.s still to go
1470 if confUsers:
1471 # this means that some C.U.s could not be applied because of a dependency loop
1472 raise Error("Detected loop in the ConfigurableUser "
1473 " dependencies: %r" % [ c.name()
1474 for c in confUsers ])
1475 # ensure that all the Handles have been triggered
1476 known = set()
1477 unknown = set(Configurable.allConfigurables)
1478 while unknown:
1479 for k in unknown:
1480 if not known: # do not print during the first iteration
1481 log.debug('new configurable created automatically: %s', k)
1482 # this trigger the instantiation from handles
1483 Configurable.allConfigurables[k].properties()
1484 known.add(k)
1485 unknown -= known
1486 # Call post-config actions
1487 for action in postConfigActions:
1488 action()
1489
1490 def getNeededConfigurables():
1491 """
1492 Function to select all and only the configurables that have to be used in
1493 GaudiPython.AppMgr constructor.
1494 This is needed because in Athena the implementation have to be different (the
1495 configuration is used in a different moment).
1496 """
1497 return [ k
1498 for k, v in Configurable.allConfigurables.items()
1499 if v.getGaudiType() != "User" ] # Exclude ConfigurableUser instances
1500
1501 def purge():
1502 """
1503 Clean up all configurations and configurables.
1504 """
1505 for c in Configurable.allConfigurables.values():
1506 c.__class__.configurables.clear()
1507 Configurable.allConfigurables.clear()
1508 # FIXME: (MCl) this is needed because instances of ConfigurableGeneric are not
1509 # migrated to the correct class when this is known.
1510 ConfigurableGeneric.configurables.clear()
1511 from ProcessJobOptions import _included_files
1512 import os.path, sys
1513 for file in _included_files:
1514 dirname, basname = os.path.split(file)
1515 basname, ext = os.path.splitext(basname)
1516 if basname in sys.modules:
1517 del sys.modules[basname]
1518 _included_files.clear()
GaudiKernel.Configurable.getNeededConfigurables
def getNeededConfigurables()
Definition: Configurable.py:1490
GaudiKernel.Configurable.Configurable.__deepcopy__
def __deepcopy__(self, memo)
Definition: Configurable.py:336
GaudiKernel.Configurable.Configurable.__children
__children
Definition: Configurable.py:284
GaudiKernel.Configurable.Configurable.setParent
def setParent(self, parentName)
Definition: Configurable.py:449
GaudiKernel.Configurable.ConfigurableUser.__apply_configuration__
def __apply_configuration__(self)
Definition: Configurable.py:1289
GaudiKernel.Configurable.Configurable.getTitleName
def getTitleName(self)
Definition: Configurable.py:714
GaudiKernel.Configurable.ConfigurableUser.__users__
__users__
Definition: Configurable.py:1156
GaudiKernel.Configurable.Configurable.removeAll
def removeAll(self)
Definition: Configurable.py:442
GaudiKernel.Configurable.ConfigurableAlgorithm.__deepcopy__
def __deepcopy__(self, memo)
Definition: Configurable.py:991
GaudiKernel.Configurable.PropertyReference.__resolve__
def __resolve__(self)
Definition: Configurable.py:63
GaudiKernel.Configurable.ConfigurableUser.__detach_used__
def __detach_used__(self)
Definition: Configurable.py:1220
GaudiKernel.Configurable.Configurable.__setstate__
def __setstate__(self, dict)
Definition: Configurable.py:322
GaudiKernel.Configurable.ConfigurableUser.__queried_configurables__
list __queried_configurables__
list of ConfigurableUser classes this one is going to query in the apply_configuration method ...
Definition: Configurable.py:1150
GaudiKernel.Configurable.Configurable._printHeader
def _printHeader(indentStr, title)
Definition: Configurable.py:828
GaudiKernel.ConfigurableMeta
Definition: ConfigurableMeta.py:1
GaudiKernel.Configurable.ConfigurableUser.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:1213
GaudiKernel.Configurable.ConfigurableUser.__init__
def __init__(self, name=Configurable.DefaultName, _enabled=True, kwargs)
Definition: Configurable.py:1151
GaudiKernel.Configurable.Configurable.setup
def setup(self)
Definition: Configurable.py:535
GaudiKernel.GaudiHandles
Definition: GaudiHandles.py:1
GaudiKernel.Configurable.ConfigurableUser.__addPassiveUseOf
def __addPassiveUseOf(self, other)
Definition: Configurable.py:1205
GaudiKernel.Configurable.Configurable.getProp
def getProp(self, name)
Definition: Configurable.py:655
GaudiKernel.Configurable.ConfigurableAuditor.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:1124
GaudiKernel.Configurable.ConfigurableAlgTool._jobOptName
_jobOptName
Definition: Configurable.py:1039
GaudiKernel.Configurable.ConfigurableUser.applyConf
def applyConf(self)
Definition: Configurable.py:1298
GaudiKernel.Configurable.Configurable.__new__
def __new__(cls, args, kwargs)
Definition: Configurable.py:121
GaudiKernel.Configurable.Configurable.splitName
def splitName(self)
Definition: Configurable.py:752
GaudiKernel.Configurable.ConfigurableAlgorithm.getJobOptName
def getJobOptName(self)
Definition: Configurable.py:1000
GaudiKernel.Configurable.Configurable.__init__
def __init__
Definition: Configurable.py:256
GaudiKernel.Configurable.Configurable.hasParent
def hasParent(self, parent)
Definition: Configurable.py:455
GaudiKernel.Configurable.appendPostConfigAction
def appendPostConfigAction(function)
Definition: Configurable.py:1340
GaudiKernel.Configurable.ConfigurableUser.propagateProperty
def propagateProperty
Definition: Configurable.py:1229
GaudiKernel.Configurable.Configurable.getPrintTitle
def getPrintTitle(self)
Definition: Configurable.py:711
GaudiKernel.Configurable.Configurable.getTools
def getTools(self)
Definition: Configurable.py:481
GaudiKernel.Configurable.Configurable.getPropertiesWithDescription
def getPropertiesWithDescription(self)
Definition: Configurable.py:577
GaudiKernel.Configurable.ConfigurableUser.propagateProperties
def propagateProperties
Definition: Configurable.py:1278
GaudiKernel.Configurable.Configurable.__setupDefaults
def __setupDefaults(self)
Definition: Configurable.py:820
GaudiKernel.Configurable.Configurable._printFooter
def _printFooter(indentStr, title)
Definition: Configurable.py:835
GaudiKernel.Configurable.ConfigurableAlgTool.setParent
def setParent(self, parentName)
Definition: Configurable.py:1061
GaudiKernel.Configurable.DummyDescriptor.__init__
def __init__(self, name)
Definition: Configurable.py:936
GaudiKernel.Configurable.Configurable._initok
_initok
Definition: Configurable.py:300
GaudiKernel.Configurable.applyConfigurableUsers
def applyConfigurableUsers()
Definition: Configurable.py:1359
GaudiKernel.Configurable.ConfigurableAlgTool.getPrintTitle
def getPrintTitle(self)
Definition: Configurable.py:1054
GaudiKernel.Configurable.Configurable.clone
def clone(self, name=None, kwargs)
Definition: Configurable.py:723
GaudiKernel.Configurable.ConfigurableUser._instanceName
def _instanceName(self, cls)
Definition: Configurable.py:1305
GaudiKernel.Configurable.Configurable.setProp
def setProp(self, name, value)
Definition: Configurable.py:663
GaudiKernel.Configurable.ConfigurableAuditor.getHandle
def getHandle(self)
Definition: Configurable.py:1120
GaudiKernel.Configurable.ConfigurableAlgTool.getParent
def getParent(self)
Definition: Configurable.py:1075
GaudiKernel.GaudiHandles.PrivateToolHandle
Definition: GaudiHandles.py:80
GaudiKernel.Configurable.ConfigurableUser.__used_configurables__
list __used_configurables__
list of ConfigurableUser classes this one is going to modify in the apply_configuration method...
Definition: Configurable.py:1147
GaudiKernel.Configurable.ConfigurableGeneric.__deepcopy__
def __deepcopy__(self, memo)
Definition: Configurable.py:953
GaudiKernel.Configurable.ConfigurableAlgTool.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:1045
GaudiKernel.Configurable.ConfigurableAlgTool.isInToolSvc
def isInToolSvc(self)
Definition: Configurable.py:1091
GaudiKernel.PropertyProxy
Definition: PropertyProxy.py:1
GaudiKernel.Configurable.ConfigurableUser.getHandle
def getHandle(self)
Definition: Configurable.py:1217
GaudiKernel.Configurable.Configurable.__getnewargs__
def __getnewargs__(self)
Definition: Configurable.py:319
GaudiKernel.Configurable.Configurable.properties
def properties(self)
Definition: Configurable.py:614
GaudiKernel.Configurable.Configurable.__getattr__
def __getattr__(self, attr)
Definition: Configurable.py:384
GaudiKernel.Configurable.ConfigurableAlgTool.getJobOptName
def getJobOptName(self)
Definition: Configurable.py:1085
GaudiKernel.Configurable.Configurable.__setupDlls
def __setupDlls(self)
Definition: Configurable.py:809
GaudiKernel.PropertyProxy.PropertyProxy
Definition: PropertyProxy.py:62
GaudiKernel.Configurable.ConfigurableAlgTool.toStringProperty
def toStringProperty(self)
Definition: Configurable.py:1094
GaudiKernel.Configurable.PropertyReference.__init__
def __init__(self, propname)
Definition: Configurable.py:59
GaudiKernel.Configurable.ConfigurableAlgorithm.__init__
def __init__
Definition: Configurable.py:986
GaudiKernel.Configurable.PropertyReference.name
name
Definition: Configurable.py:60
GaudiKernel.ConfigurableDb
Definition: ConfigurableDb.py:1
GaudiKernel.Configurable.ConfigurableService.__deepcopy__
def __deepcopy__(self, memo)
Definition: Configurable.py:1008
GaudiKernel.Configurable.ConfigurableService.getHandle
def getHandle(self)
Definition: Configurable.py:1014
GaudiKernel.Configurable.PropertyReference.getFullName
def getFullName(self)
Definition: Configurable.py:75
GaudiKernel.Configurable.ConfigurableAlgTool.__init__
def __init__
Definition: Configurable.py:1032
GaudiKernel.Configurable.Configurable.name
def name(self)
Definition: Configurable.py:690
GaudiKernel.Configurable.Configurable.copyChildAndSetParent
def copyChildAndSetParent(self, cfg, parent)
Definition: Configurable.py:458
GaudiKernel.Configurable.ConfigurableGeneric.__setattr__
def __setattr__(self, name, value)
Definition: Configurable.py:960
GaudiKernel.Configurable.Configurable.remove
def remove(self, items)
Definition: Configurable.py:436
GaudiKernel.Configurable.Configurable.children
def children(self)
Definition: Configurable.py:484
GaudiKernel.Configurable.Configurable.__iadd__
def __iadd__
Definition: Configurable.py:352
GaudiKernel.Configurable.ConfigurableUser.__addActiveUseOf
def __addActiveUseOf(self, other)
Definition: Configurable.py:1197
gaudirun.type
string type
Definition: gaudirun.py:151
GaudiKernel.Configurable.ConfigurableUser.isApplicable
def isApplicable(self)
Definition: Configurable.py:1331
GaudiKernel.Configurable.Configurable._name
_name
Definition: Configurable.py:290
GaudiKernel.Configurable.Configurable._setupok
_setupok
Definition: Configurable.py:303
GaudiKernel.Configurable.Configurable.__nonzero__
def __nonzero__(self)
Definition: Configurable.py:432
GaudiKernel.Configurable.Configurable.getFullName
def getFullName(self)
Definition: Configurable.py:705
GaudiKernel.Configurable.Configurable.setDefaults
def setDefaults(cls, handle)
Definition: Configurable.py:720
GaudiKernel.Configurable.Configurable.getSequence
def getSequence(self)
Definition: Configurable.py:529
GaudiKernel.Configurable.ConfigurableAlgTool.getGaudiHandle
def getGaudiHandle(self)
Definition: Configurable.py:1048
GaudiKernel.Configurable.ConfigurableUser._enabled
_enabled
Definition: Configurable.py:1155
GaudiKernel.Configurable.ConfigurableAlgorithm.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:997
GaudiKernel.Configurable.Configurable.addTool
def addTool
Definition: Configurable.py:768
GaudiKernel.Configurable.ConfigurableAuditor.getJobOptName
def getJobOptName(self)
Definition: Configurable.py:1127
GaudiKernel.Configurable.ConfigurableUser.getDlls
def getDlls(self)
Definition: Configurable.py:1215
GaudiKernel.Configurable.Configurable.isPropertySet
def isPropertySet(self, name)
Definition: Configurable.py:668
GaudiKernel.Configurable.ConfigurableAuditor.toStringProperty
def toStringProperty(self)
Definition: Configurable.py:1130
GaudiKernel.Configurable.ConfigurableAlgTool.getFullName
def getFullName(self)
Definition: Configurable.py:1098
GaudiKernel.Configurable.Configurable.getProperties
def getProperties(self)
Definition: Configurable.py:567
GaudiKernel.Configurable.Configurable.getDefaultProperties
def getDefaultProperties(cls)
Definition: Configurable.py:618
GaudiKernel.Configurable.ConfigurableUser._applied
_applied
Definition: Configurable.py:1157
GaudiKernel.Configurable.PropertyReference.__repr__
def __repr__(self)
Definition: Configurable.py:61
GaudiKernel.Configurable.Configurable.getJobOptName
def getJobOptName(self)
Definition: Configurable.py:693
GaudiKernel.GaudiHandles.PublicToolHandle
Definition: GaudiHandles.py:71
GaudiKernel.Configurable.Configurable.__delattr__
def __delattr__(self, attr)
Definition: Configurable.py:407
GaudiKernel.Configurable.Configurable
Definition: Configurable.py:89
GaudiKernel.Configurable.ConfigurableUser.getUsedInstance
def getUsedInstance(self, name)
Definition: Configurable.py:1318
GaudiKernel.Configurable.ConfigurableGeneric.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:956
GaudiKernel.ConfigurableMeta.ConfigurableMeta
this metaclass installs PropertyProxy descriptors for Gaudi properties
Definition: ConfigurableMeta.py:14
GaudiKernel.Configurable.ConfigurableAuditor
Definition: Configurable.py:1110
GaudiKernel.Constants
Definition: Constants.py:1
GaudiKernel.Configurable.ConfigurableService
Definition: Configurable.py:1004
GaudiKernel.Configurable.ConfigurableAlgTool.isPublic
def isPublic(self)
Definition: Configurable.py:1088
GaudiKernel.Configurable.ConfigurableService.copyChild
def copyChild(self, child)
Definition: Configurable.py:1011
GaudiKernel.Configurable.ConfigurableGeneric.__init__
def __init__
Definition: Configurable.py:948
GaudiKernel.Configurable.applyConfigurableUsers_old
def applyConfigurableUsers_old()
Definition: Configurable.py:1428
GaudiKernel.Configurable.Configurable.getParent
def getParent(self)
Definition: Configurable.py:452
GaudiPython.GaudiAlgs.iAlgorithm
iAlgorithm
The basic module.
Definition: GaudiAlgs.py:54
GaudiKernel.Configurable.Configurable.getName
def getName(self)
Definition: Configurable.py:687
GaudiKernel.Configurable.Configurable.getFullJobOptName
def getFullJobOptName(self)
Definition: Configurable.py:708
compareRootHistos.action
string action
Definition: compareRootHistos.py:320
GaudiKernel.Configurable.Configurable.__len__
def __len__(self)
Definition: Configurable.py:329
GaudiKernel.Configurable.DummyDescriptor.__set__
def __set__(self, obj, value)
Definition: Configurable.py:942
GaudiKernel.Configurable.removePostConfigAction
def removePostConfigAction(function)
Definition: Configurable.py:1351
GaudiKernel.Configurable.ConfigurableAlgTool.hasParent
def hasParent(self, parent)
Definition: Configurable.py:1082
GaudiKernel.GaudiHandles.ServiceHandle
Definition: GaudiHandles.py:89
GaudiKernel.Configurable.ConfigurableAlgorithm._jobOptName
_jobOptName
Definition: Configurable.py:989
GaudiKernel.Configurable.ConfigurableGeneric.getHandle
def getHandle(self)
Definition: Configurable.py:958
GaudiKernel.Configurable.Configurable.jobOptName
def jobOptName(self)
Definition: Configurable.py:700
GaudiKernel.Configurable.Configurable.__setupServices
def __setupServices(self)
Definition: Configurable.py:792
GaudiKernel.Configurable.ConfigurableService.getGaudiType
def getGaudiType(self)
Definition: Configurable.py:1017
GaudiKernel.Configurable.DummyDescriptor
classes for generic Gaudi component ===========
Definition: Configurable.py:935
GaudiKernel.Configurable.expandvars
def expandvars(data)
Definition: Configurable.py:29
GaudiKernel.Configurable.Configurable._isInSetDefaults
def _isInSetDefaults(self)
Definition: Configurable.py:789
GaudiKernel.Configurable.ConfigurableUser
Definition: Configurable.py:1134
GaudiKernel.Configurable.DummyDescriptor.__name__
__name__
Definition: Configurable.py:937
gaudiComponentHelp.properties
tuple properties
Definition: gaudiComponentHelp.py:37
GaudiKernel.Configurable.Configurable.isPublic
def isPublic(self)
Definition: Configurable.py:696
GaudiKernel.DataObjectHandleBase
Definition: DataObjectHandleBase.py:1
GaudiKernel.Configurable.ConfigurableGeneric.getJobOptName
def getJobOptName(self)
Definition: Configurable.py:976
GaudiKernel.Configurable.Configurable.getDefaultProperty
def getDefaultProperty(cls, name)
Definition: Configurable.py:634
GaudiKernel.Configurable.Configurable.getChildren
def getChildren(self)
Definition: Configurable.py:478
GaudiKernel.Configurable.ConfigurableService.toStringProperty
def toStringProperty(self)
Definition: Configurable.py:1023
GaudiKernel.Configurable.purge
def purge()
Definition: Configurable.py:1501
GaudiKernel.Configurable.DummyDescriptor.__get__
def __get__
Definition: Configurable.py:939
GaudiKernel.Configurable.ConfigurableUser.__used_instances__
__used_instances__
Definition: Configurable.py:1165
GaudiKernel.Configurable.ConfigurableAlgorithm.getHandle
def getHandle(self)
Definition: Configurable.py:994
GaudiKernel.Configurable.Configurable.copyChild
def copyChild(self, child)
Definition: Configurable.py:446
GaudiKernel.Configurable.ConfigurableGeneric
Definition: Configurable.py:945
GaudiKernel.Configurable.Configurable.getValuedProperties
def getValuedProperties(self)
Definition: Configurable.py:587
GaudiKernel.Configurable.Configurable.__setattr__
def __setattr__(self, name, value)
Definition: Configurable.py:398
GaudiKernel.Configurable.isApplicable
def isApplicable(self)
if isinstance(v,Configurable) and not v.isPublic(): rep += v.__str__( indent + 1 ) + os...
Definition: Configurable.py:926
GaudiKernel.Configurable.Configurable.getType
def getType(cls)
Definition: Configurable.py:684
GaudiKernel.Configurable.Configurable.__repr__
def __repr__(self)
Definition: Configurable.py:841
GaudiKernel.Configurable.Configurable.__slots__
tuple __slots__
Definition: Configurable.py:106
GaudiKernel.Configurable.ConfigurableAuditor.__init__
def __init__
Definition: Configurable.py:1114
GaudiKernel.Configurable.Configurable.__getstate__
def __getstate__(self)
Definition: Configurable.py:306
GaudiKernel.Configurable.ConfigurableGeneric._properties
_properties
Definition: Configurable.py:951
GaudiKernel.Configurable.ConfigurableAlgTool
Definition: Configurable.py:1028
GaudiKernel.Configurable.Configurable._configurationLocked
_configurationLocked
Definition: Configurable.py:119
GaudiKernel.Configurable.ConfigurableAuditor._jobOptName
_jobOptName
Definition: Configurable.py:1118
GaudiKernel.Configurable.ConfigurableService.getGaudiHandle
def getGaudiHandle(self)
Definition: Configurable.py:1020
GaudiKernel.Configurable.Configurable.__tools
__tools
Definition: Configurable.py:285
GaudiKernel.Configurable.ConfigurableAlgTool.getHandle
def getHandle(self)
Definition: Configurable.py:1041
GaudiKernel.Configurable.Configurable.__str__
def __str__
Definition: Configurable.py:844
GaudiKernel.Configurable.Error
Definition: Configurable.py:51
GaudiKernel.Configurable.Configurable.__iter__
def __iter__(self)
Definition: Configurable.py:332
GaudiKernel.Configurable.Configurable._inSetDefaults
_inSetDefaults
Definition: Configurable.py:297
GaudiKernel.Configurable.Configurable.getAllChildren
def getAllChildren(self)
Definition: Configurable.py:490
GaudiKernel.Configurable.Configurable.DefaultName
for detecting the default name
Definition: Configurable.py:96