![]() |
|
|
Generated: 8 Jan 2009 |
00001 # File: AthenaCommon/python/ConfigurableMeta.py 00002 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov) 00003 00004 import GaudiKernel.PropertyProxy as PropertyProxy 00005 00006 00007 ### data 00008 __version__ = '1.0.1' 00009 __author__ = 'Wim Lavrijsen (WLavrijsen@lbl.gov)' 00010 00011 __all__ = [ 'ConfigurableMeta' ] 00012 00013 ### this metaclass installs PropertyProxy descriptors for Gaudi properties 00014 class ConfigurableMeta( type ): 00015 """The setting of Gaudi component properties needs to be deferred and 00016 history of who set what where needs to be collected. This is done 00017 by using PropertyProxy descriptors rather than the default ones.""" 00018 00019 def __new__( self, name, bases, dct ): 00020 # enfore use of classmethod for getType() and setDefaults() 00021 if 'getType' in dct and not isinstance( dct[ 'getType' ], classmethod ): 00022 dct[ 'getType' ] = classmethod( dct[ 'getType' ] ) 00023 00024 if 'setDefaults' in dct and not isinstance( dct[ 'setDefaults' ], classmethod ): 00025 dct[ 'setDefaults' ] = classmethod( dct[ 'setDefaults' ] ) 00026 00027 # collect what are properties (basically, any public name; C++ variables 00028 # shouldn't start with an '_' because of portability constraints, hence 00029 # it is safe to assume that any such vars are python private ones) 00030 newclass = type.__new__( self, name, bases, dct ) 00031 00032 # cache references of instances by name for duplicate removal 00033 newclass.configurables = {} 00034 00035 # loop over slots, which are all assumed to be properties, create proxies, defaults 00036 properties = {} 00037 slots = dct.get( '__slots__' ) 00038 if slots: 00039 props = [ x for x in slots if x[0] != '_' ] 00040 propDict = dct.get('_propertyDocDct') 00041 for prop in props: 00042 docString = propDict and propDict.get(prop) 00043 if type(slots) == dict: 00044 default = slots[prop] 00045 else: 00046 default = None 00047 proxy = PropertyProxy.PropertyProxyFactory( getattr( newclass, prop ), docString, default ) 00048 00049 properties[ prop ] = proxy 00050 setattr( newclass, prop, proxy ) 00051 00052 # complete set of properties includes those from base classes 00053 for base in bases: 00054 try: 00055 bprops = base._properties.copy() 00056 bprops.update( properties ) 00057 properties = bprops 00058 except AttributeError: 00059 pass 00060 00061 newclass._properties = properties 00062 00063 return newclass 00064 00065 def __call__( cls, *args, **kwargs ): 00066 """To Gaudi, any object with the same type/name is the same object. Hence, 00067 this is mimicked in the configuration: instantiating a new Configurable 00068 of a type with the same name will return the same instance.""" 00069 00070 # Get the instance: `singleton' logic needs to be in __new__, not here, 00071 # for compatibililty with pickling.) 00072 cfg = cls.__new__( cls, *args, **kwargs ) 00073 00074 # Initialize the object, if not done already. 00075 if not hasattr(cfg, '_initok') or not cfg._initok: 00076 cls.__init__( cfg, *args, **kwargs ) 00077 00078 return cfg