6 __all__ = [
'PropertyProxy',
'GaudiHandlePropertyProxy',
'GaudiHandleArrayPropertyProxy' ]
10 from GaudiKernel
import ConfigurableDb
13 log = logging.getLogger(
'PropertyProxy' )
20 """A string version of isinstance().
21 <derived> is either an object instance, or a type
22 <base> is a string containing the name of the base class (or <derived> class)"""
23 if not isinstance(derived,type): derived=
type(derived)
24 if derived.__name__ == base:
return True
25 for b
in derived.__bases__:
31 errmsg =
"received an instance of %s, but %s expected" % (
type(value),tp)
41 raise ValueError( errmsg )
42 elif ( tp
in [ list, tuple, dict ] ):
43 if (
type(value)
is tp ):
48 raise ValueError( errmsg )
55 except (TypeError,ValueError):
56 raise ValueError( errmsg )
61 class PropertyProxy( object ):
62 def __init__( self, descr, docString=None, default=None ):
66 self.__doc__ = docString
67 if default
is not None:
68 self.default = default
71 def setDefault( self, value ):
72 self.__default = value
74 def getDefault( self ):
77 default = property( getDefault, setDefault )
79 def fullPropertyName( self, obj ):
80 return (obj.getJobOptName()
or obj.getName()) +
'.' + self.descr.__name__
82 def __get__( self, obj, type = None ):
84 return self.descr.__get__( obj, type )
85 except AttributeError:
88 if self.__default.__class__
in [ list, dict ]:
89 self.descr.__set__( obj, self.__default.__class__(self.__default) )
90 return self.descr.__get__( obj, type )
96 def __set__( self, obj, value ):
98 proptype, allowcompat =
None,
False
99 if hasattr( self,
'default' ):
100 proptype =
type(self.default)
101 if self.descr.__name__ ==
'OutputLevel':
103 elif obj
in self.history:
104 proptype =
type( self.history[ obj ][ 0 ] )
110 if proptype
and proptype !=
type(
None)
and \
119 oldvec = self.descr.__get__( obj, type )
121 tpo =
type(oldvec[0])
124 except AttributeError:
127 except ValueError, e:
129 log.error(
'inconsistent value types for %s.%s (%s)' %\
130 (obj.getName(),self.descr.__name__,str(e)) )
136 if not obj._isInSetDefaults()
or not obj
in self.history:
138 if hasattr( self,
'default' )
and self.default ==
None:
139 obj.__iadd__( value, self.descr )
141 self.descr.__set__( obj, value )
142 self.history.setdefault( obj, [] ).append( value )
144 def __delete__( self, obj ):
145 if obj
in self.history:
146 del self.history[ obj ]
147 self.descr.__delete__( obj )
151 class GaudiHandlePropertyProxyBase(PropertyProxy):
152 """A class with some utilities for GaudiHandles and GaudiHandleArrays"""
154 def __init__(self, descr, docString, default, handleType, allowedType ):
155 """<descr>: the real property in the object instance (from __slots__)
156 <docString>: the documentation string of this property
157 <default>: default value from C++ (via python generated by genconf)
158 <handleType>: real python handle type (e.g. PublicToolHandle, PrivateToolHandle, ...)
159 <allowedType>: allowed instance type for default
162 if not isinstance(default,allowedType):
163 raise TypeError(
"%s: %s default: %r is not a %s" % \
164 ( descr.__name__, self.__class__.__name__, default, allowedType.__name__ ) )
165 PropertyProxy.__init__( self, descr, docString, default )
166 self._handleType = handleType
167 self._confTypeName =
'Configurable' + handleType.componentType
171 def __get__( self, obj, type = None ):
173 return self.descr.__get__( obj, type )
174 except AttributeError:
177 default = obj.__class__.getDefaultProperty( self.descr.__name__ )
178 default = self.convertDefaultToBeSet( obj, default )
180 self.__set__( obj, default )
181 except AttributeError,e:
183 raise RuntimeError(*e.args)
185 return self.descr.__get__( obj, type )
188 def __set__( self, obj, value ):
191 if not obj._isInSetDefaults()
or not obj
in self.history:
192 value = self.convertValueToBeSet( obj, value )
194 self.descr.__set__( obj, value )
195 log.debug(
"Setting %s = %r", self.fullPropertyName( obj ), value )
196 self.history.setdefault( obj, [] ).append( value )
200 def isHandle(self,value):
201 """Check if <value> is a handle of the correct type"""
202 return isinstance(value,self._handleType)
205 def isConfig(self,value):
206 """Check if <value> is a configurable of the correct type"""
210 def getDefaultConfigurable(self,typeAndName,requester):
211 """Return the configurable instance corresponding to the toolhandle if possible.
212 Otherwise return None"""
215 typeAndNameTuple = typeAndName.split(
'/')
216 confType = typeAndNameTuple[0]
217 confClass=ConfigurableDb.getConfigurable(confType)
220 log.error(
"%s: Configurable %s is not a %s",
221 requester, confType, self._confTypeName )
224 confName = typeAndNameTuple[1]
228 return confClass(confName)
231 def convertDefaultToBeSet( self, obj, default ):
233 isString =
type(default) == str
234 if not isString
and self.isConfig(default):
237 elif isString
or self.isHandle(default):
240 typeAndName = default
241 default = self._handleType( typeAndName )
243 typeAndName = default.typeAndName
244 if not self._handleType.isPublic:
249 conf = self.getDefaultConfigurable(typeAndName, self.fullPropertyName(obj))
251 except AttributeError,e:
253 raise RuntimeError(*e.args)
255 raise RuntimeError(
"%s: Default configurable for class %s not found in ConfigurableDb.CfgDb" % \
256 (self.fullPropertyName(obj),default.getType() ) )
259 raise TypeError(
"%s: default value %r is not of type %s or %s" % \
260 (self.fullPropertyName(obj),default,self._confTypeName,self._handleType.__name__) )
264 def convertValueToBeSet( self, obj, value ):
265 if value
is None: value =
''
266 isString =
type(value) == str
269 return self._handleType(value)
270 elif self.isHandle(value):
272 return self._handleType(value.toStringProperty())
273 elif self.isConfig(value):
274 if self._handleType.isPublic:
277 if not value.isInToolSvc():
278 suggestion =
'You may need to add jobOptions lines something like:' + os.linesep + \
279 'from AthenaCommon.AppMgr import ToolSvc' + os.linesep + \
281 if value.getName() == value.getType():
282 suggestion +=
'%s()' % value.__class__.__name__
284 suggestion +=
'%s(%r)' % (value.__class__.__name__,value.getName())
285 raise RuntimeError( self.fullPropertyName(obj) +
286 ': Public tool %s is not yet in ToolSvc. %s' %
287 (value.getJobOptName(),suggestion) )
289 return self._handleType(value.toStringProperty())
290 elif value.hasParent( obj.getJobOptName() ):
295 value = obj.copyChildAndSetParent( value, obj.getJobOptName() )
297 obj.allConfigurables[value.name()] = value
300 raise TypeError(
"Property %s value %r is not a %s nor a %s nor a string" % \
301 (self.fullPropertyName(obj),value,self._confTypeName,self._handleType.__name__) )
306 class GaudiHandlePropertyProxy(GaudiHandlePropertyProxyBase):
307 def __init__( self, descr, docString, default ):
308 GaudiHandlePropertyProxyBase.__init__( self, descr, docString, default,
type(default), GaudiHandle )
311 class GaudiHandleArrayPropertyProxy(GaudiHandlePropertyProxyBase):
312 def __init__( self, descr, docString, default ):
313 """<descr>: the real property in the object instance (from __slots__)
314 <confTypeName>: string indicating the (base) class of allowed Configurables to be assigned.
315 <handleType>: real python handle type (e.g. PublicToolHandle, PrivateToolHandle, ...)
317 GaudiHandlePropertyProxyBase.__init__( self, descr, docString, default,
type(default).handleType, GaudiHandleArray )
318 self.arrayType =
type(default)
321 def checkType( self, obj, value ):
322 if not isinstance( value, list )
and not isinstance( value, self.arrayType ):
323 raise TypeError(
"%s: Value %r is not a list nor a %s" % \
324 ( self.fullPropertyName(obj), value, self.arrayType.__name__ ) )
327 def convertDefaultToBeSet( self, obj, default ):
328 self.checkType( obj, default )
329 newDefault = self.arrayType()
331 cd = GaudiHandlePropertyProxyBase.convertDefaultToBeSet( self, obj, d )
332 if cd: newDefault.append( cd )
337 def convertValueToBeSet( self, obj, value ):
338 self.checkType( obj, value )
339 newValue = self.arrayType()
341 cv = GaudiHandlePropertyProxyBase.convertValueToBeSet( self, obj, v )
342 if cv: newValue.append( cv )
350 if isinstance(default,GaudiHandleArray):
351 return GaudiHandleArrayPropertyProxy( descr, doc, default )
353 if isinstance(default,GaudiHandle):
354 return GaudiHandlePropertyProxy( descr, doc, default )
356 return PropertyProxy( descr, doc, default )
def _isCompatible(tp, value)
def derives_from(derived, base)
def PropertyProxyFactory(descr, doc, default)