| The Gaudi Framework v27r1

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

- File List
- File Members

PropertyProxy.py
Go to the documentation of this file.
1 # File: AthenaCommon/python/PropertyProxy.py
2 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
3 # Author: Martin Woudstra (Martin.Woudstra@cern.ch)
4
5 ### data ---------------------------------------------------------------------
6 __all__ = [ 'PropertyProxy', 'GaudiHandlePropertyProxy', 'GaudiHandleArrayPropertyProxy' ]
7
8 import os,glob
9 from GaudiKernel.GaudiHandles import *
10 from GaudiKernel import ConfigurableDb
11 from GaudiKernel.DataObjectHandleBase import *
12
13 import logging
14 log = logging.getLogger( 'PropertyProxy' )
15
16 # dictionary with configurable class : python module entries
17 #-->PM#from AthenaCommon import ConfigurableDb
18
19
20 def derives_from(derived,base):
21 """A string version of isinstance().
22 <derived> is either an object instance, or a type
23 <base> is a string containing the name of the base class (or <derived> class)"""
24 if not isinstance(derived,type): derived=type(derived)
25 if derived.__name__ == base: return True
26 for b in derived.__bases__:
27 if derives_from(b,base): return True
28
29 return False
30
31 def _isCompatible( tp, value ):
32 errmsg = "received an instance of %s, but %s expected" % (type(value),tp)
33
34 if derives_from(value, 'PropertyReference'):
35 # TODO: implement type checking for references
36 return value # references are valid
37 if ( tp is str ):
38 if ( type(value) is str ) or derives_from(value, 'Configurable'):
39 # we can set string properties only from strings or configurables
40 return value
41 else:
42 raise ValueError( errmsg )
43 elif ( tp in [ list, tuple, dict ] ):
44 if ( type(value) is tp ):
45 # We need to check that the types match for lists, tuples and
46 # dictionaries (bug #34769).
47 return value
48 else:
49 raise ValueError( errmsg )
50 elif derives_from(tp, 'Configurable'):
51 return value
52 else:
53 # all other types: accept if conversion allowed
54 try:
55 dummy = tp( value )
56 except (TypeError,ValueError):
57 raise ValueError( errmsg )
58
59 return dummy # in case of e.g. classes with __int__, __iter__, etc. implemented
60
61
62 class PropertyProxy( object ):
63 def __init__( self, descr, docString=None, default=None ):
64 self.history = {}
65 self.descr = descr
66 if docString:
67 self.__doc__ = docString
68 if default is not None:
69 self.default = default
70
71
72 def setDefault( self, value ):
73 self.__default = value
74
75 def getDefault( self ):
76 return self.__default
77
78 default = property( getDefault, setDefault )
79
80 def fullPropertyName( self, obj ):
81 return (obj.getJobOptName() or obj.getName()) + '.' + self.descr.__name__
82
83 def __get__( self, obj, type = None ):
84 try:
85 return self.descr.__get__( obj, type )
86 except AttributeError:
87 # special case for lists and dictionaries:
88 # allow default to work with on += and []
89 if self.__default.__class__ in [ list, dict ]:
90 self.descr.__set__( obj, self.__default.__class__(self.__default) )
91 return self.descr.__get__( obj, type )
92 else:
93 # for non lists (or dicts) return a reference to the default
94 #return self.__default
95 raise
96
97 def __set__( self, obj, value ):
98 # check value/property compatibility if possible
99 proptype, allowcompat = None, False
100 if hasattr( self, 'default' ):
101 proptype = type(self.default)
102 if self.descr.__name__ == 'OutputLevel': # old-style compat for Btag
103 allowcompat = True
104 elif obj in self.history:
105 proptype = type( self.history[ obj ][ 0 ] )
106 allowcompat = True
107
108 # check if type known; allow special initializer for typed instances
109 # Do not perform the check for PropertyReference, should be delayed until
110 # binding (if ever done)
111 if proptype and proptype != type(None) and \
112 not derives_from(value, 'PropertyReference'):
113 try:
114 # check value itself
115 value = _isCompatible( proptype, value )
116
117 # check element in case of list
118 if proptype == list:
119 try:
120 oldvec = self.descr.__get__( obj, type )
121 if oldvec:
122 tpo = type(oldvec[0])
123 for v in value:
124 _isCompatible( tpo, v )
125 except AttributeError:
126 # value not yet set
127 pass
128 except ValueError, e:
129 if allowcompat:
130 log.error( 'inconsistent value types for %s.%s (%s)' %\
131 (obj.getName(),self.descr.__name__,str(e)) )
132 else:
133 raise
134
135 # allow a property to be set if we're in non-default mode, or if it
136 # simply hasn't been set before
137 if not obj._isInSetDefaults() or not obj in self.history:
138 # by convention, 'None' for default is used to designate objects setting
139 if hasattr( self, 'default' ) and self.default == None:
140 obj.__iadd__( value, self.descr ) # to establish hierarchy
141 else:
142 self.descr.__set__( obj, value )
143 self.history.setdefault( obj, [] ).append( value )
144
145 def __delete__( self, obj ):
146 if obj in self.history:
147 del self.history[ obj ]
148 self.descr.__delete__( obj )
149
150
151
152 class GaudiHandlePropertyProxyBase(PropertyProxy):
153 """A class with some utilities for GaudiHandles and GaudiHandleArrays"""
154
155 def __init__(self, descr, docString, default, handleType, allowedType ):
156 """<descr>: the real property in the object instance (from __slots__)
157 <docString>: the documentation string of this property
158 <default>: default value from C++ (via python generated by genconf)
159 <handleType>: real python handle type (e.g. PublicToolHandle, PrivateToolHandle, ...)
160 <allowedType>: allowed instance type for default
161 """
162 # check that default is of allowed type for this proxy
163 if not isinstance(default,allowedType):
164 raise TypeError( "%s: %s default: %r is not a %s" % \
165 ( descr.__name__, self.__class__.__name__, default, allowedType.__name__ ) )
166 PropertyProxy.__init__( self, descr, docString, default )
167 self._handleType = handleType
168 self._confTypeName = 'Configurable' + handleType.componentType
169 # print "%s: %r (%s)" % (self.__class__.__name__,self._handleType,self._confTypeName)
170
171
172 def __get__( self, obj, type = None ):
173 try:
174 return self.descr.__get__( obj, type )
175 except AttributeError:
176 # Get default
177 try:
178 default = obj.__class__.getDefaultProperty( self.descr.__name__ )
179 default = self.convertDefaultToBeSet( obj, default )
180 if default:
181 self.__set__( obj, default )
182 except AttributeError,e:
183 # change type of exception to avoid false error message
184 raise RuntimeError(*e.args)
185
186 return self.descr.__get__( obj, type )
187
188
189 def __set__( self, obj, value ):
190 # allow a property to be set if we're in non-default mode, or if it
191 # simply hasn't been set before
192 if not obj._isInSetDefaults() or not obj in self.history:
193 value = self.convertValueToBeSet( obj, value )
194 # assign the value
195 self.descr.__set__( obj, value )
196 log.debug( "Setting %s = %r", self.fullPropertyName( obj ), value )
197 self.history.setdefault( obj, [] ).append( value )
198
199
200
201 def isHandle(self,value):
202 """Check if <value> is a handle of the correct type"""
203 return isinstance(value,self._handleType)
204
205
206 def isConfig(self,value):
207 """Check if <value> is a configurable of the correct type"""
208 return derives_from(value,self._confTypeName)
209
210
211 def getDefaultConfigurable(self,typeAndName,requester):
212 """Return the configurable instance corresponding to the toolhandle if possible.
213 Otherwise return None"""
214 global log
215 # find the module
216 typeAndNameTuple = typeAndName.split('/')
217 confType = typeAndNameTuple[0]
218 confClass=ConfigurableDb.getConfigurable(confType)
219 # check the type of the configurable
220 if not derives_from(confClass,self._confTypeName):
221 log.error( "%s: Configurable %s is not a %s",
222 requester, confType, self._confTypeName )
223 return None
224 try:
225 confName = typeAndNameTuple[1]
226 except IndexError:
227 return confClass() # use default name
228 else:
229 return confClass(confName)
230
231
232 def convertDefaultToBeSet( self, obj, default ):
233 # turn string into handle
234 isString = type(default) == str
235 if not isString and self.isConfig(default):
236 # print self.fullPropertyName(obj) + ": Setting default configurable: %r" % default
237 return default
238 elif isString or self.isHandle(default):
239 if isString:
240 # convert string into handle
241 typeAndName = default
242 default = self._handleType( typeAndName )
243 else:
244 typeAndName = default.typeAndName
245 if not self._handleType.isPublic:
246 if not typeAndName:
247 return None
248 # Find corresponding default configurable of private handles
249 try:
250 conf = self.getDefaultConfigurable(typeAndName, self.fullPropertyName(obj))
251 # print self.fullPropertyName(obj) + ": Setting default private configurable (from default handle): %r" % conf
252 except AttributeError,e:
253 # change type of exception to avoid false error message
254 raise RuntimeError(*e.args)
255 if conf is None:
256 raise RuntimeError( "%s: Default configurable for class %s not found in ConfigurableDb.CfgDb" % \
257 (self.fullPropertyName(obj),default.getType() ) )
258 return conf
259 else: # not a config, not a handle, not a string
260 raise TypeError( "%s: default value %r is not of type %s or %s" % \
261 (self.fullPropertyName(obj),default,self._confTypeName,self._handleType.__name__) )
262
263 return default
264
265 def convertValueToBeSet( self, obj, value ):
266 if value is None: value = ''
267 isString = type(value) == str
268 if isString:
269 # create an new handle
270 return self._handleType(value)
271 elif self.isHandle(value):
272 # make a copy of the handle
273 return self._handleType(value.toStringProperty())
274 elif self.isConfig(value):
275 if self._handleType.isPublic:
276 # A public tool must be registered to ToolSvc before assigning it
277 if derives_from(value,'ConfigurableAlgTool'):
278 if not value.isInToolSvc():
279 suggestion = 'You may need to add jobOptions lines something like:' + os.linesep + \
280 'from AthenaCommon.AppMgr import ToolSvc' + os.linesep + \
281 'ToolSvc += '
282 if value.getName() == value.getType(): # using default name
283 suggestion += '%s()' % value.__class__.__name__
284 else: # using user-defined name
285 suggestion += '%s(%r)' % (value.__class__.__name__,value.getName())
286 raise RuntimeError( self.fullPropertyName(obj) +
287 ': Public tool %s is not yet in ToolSvc. %s' %
288 (value.getJobOptName(),suggestion) )
289 # make it read-only
290 return self._handleType(value.toStringProperty())
291 elif value.hasParent( obj.getJobOptName() ):
292 # is already a child, keep as-is
293 return value
294 else:
295 # make a copy of the configurable
296 value = obj.copyChildAndSetParent( value, obj.getJobOptName() )
297 # ensure that the new object is in allConfigurables
298 obj.allConfigurables[value.name()] = value
299 return value
300 else:
301 raise TypeError( "Property %s value %r is not a %s nor a %s nor a string" % \
302 (self.fullPropertyName(obj),value,self._confTypeName,self._handleType.__name__) )
303
304 return value
305
306
307 class GaudiHandlePropertyProxy(GaudiHandlePropertyProxyBase):
308 def __init__( self, descr, docString, default ):
309 GaudiHandlePropertyProxyBase.__init__( self, descr, docString, default, type(default), GaudiHandle )
310
311
312 class GaudiHandleArrayPropertyProxy(GaudiHandlePropertyProxyBase):
313 def __init__( self, descr, docString, default ):
314 """<descr>: the real property in the object instance (from __slots__)
315 <confTypeName>: string indicating the (base) class of allowed Configurables to be assigned.
316 <handleType>: real python handle type (e.g. PublicToolHandle, PrivateToolHandle, ...)
317 """
318 GaudiHandlePropertyProxyBase.__init__( self, descr, docString, default, type(default).handleType, GaudiHandleArray )
319 self.arrayType = type(default)
320
321
322 def checkType( self, obj, value ):
323 if not isinstance( value, list ) and not isinstance( value, self.arrayType ):
324 raise TypeError( "%s: Value %r is not a list nor a %s" % \
325 ( self.fullPropertyName(obj), value, self.arrayType.__name__ ) )
326
327
328 def convertDefaultToBeSet( self, obj, default ):
329 self.checkType( obj, default )
330 newDefault = self.arrayType()
331 for d in default:
332 cd = GaudiHandlePropertyProxyBase.convertDefaultToBeSet( self, obj, d )
333 if cd: newDefault.append( cd )
334
335 return newDefault
336
337
338 def convertValueToBeSet( self, obj, value ):
339 self.checkType( obj, value )
340 newValue = self.arrayType()
341 for v in value:
342 cv = GaudiHandlePropertyProxyBase.convertValueToBeSet( self, obj, v )
343 if cv: newValue.append( cv )
344
345 return newValue
346
347 class DataObjectHandleBasePropertyProxy(PropertyProxy):
348
349 def __init__(self, descr, docString, default):
350 PropertyProxy.__init__( self, descr, docString, default )
351
352 def __get__(self, obj, type=None):
353 try:
354 return self.descr.__get__( obj, type )
355 except AttributeError:
356 # Get default
357 try:
358 default = obj.__class__.getDefaultProperty( self.descr.__name__ )
359 default = self.convertValueToBeSet( obj, default )
360 if default:
361 self.__set__( obj, default )
362 except AttributeError,e:
363 # change type of exception to avoid false error message
364 raise RuntimeError(*e.args)
365
366 return self.descr.__get__( obj, type )
367
368 def __set__(self, obj, value):
369 if not obj._isInSetDefaults() or not obj in self.history:
370 value = self.convertValueToBeSet( obj, value )
371 # assign the value
372 self.descr.__set__( obj, value )
373 log.debug( "Setting %s = %r", self.fullPropertyName( obj ), value )
374 self.history.setdefault( obj, [] ).append( value)
375
376 def convertValueToBeSet(self, obj, value):
377 if value is None: value = ''
378
379 if type(value) == str:
380 return DataObjectHandleBase(value)
381 elif isinstance(value, DataObjectHandleBase):
382 return DataObjectHandleBase(value.__str__())
383
384
385 def PropertyProxyFactory( descr, doc, default ):
386 # print "PropertyProxyFactory( %s, %r )" % (descr.__name__,default)
387
388 if isinstance(default,GaudiHandleArray):
389 return GaudiHandleArrayPropertyProxy( descr, doc, default )
390
391 if isinstance(default,GaudiHandle):
392 return GaudiHandlePropertyProxy( descr, doc, default )
393
394 if isinstance(default,DataObjectHandleBase):
395 return DataObjectHandleBasePropertyProxy( descr, doc, default )
396
397 return PropertyProxy( descr, doc, default )
GaudiKernel.PropertyProxy.PropertyProxy.__get__
def __get__
Definition: PropertyProxy.py:83
GaudiKernel.PropertyProxy.PropertyProxy.history
history
Definition: PropertyProxy.py:64
GaudiKernel.PropertyProxy.DataObjectHandleBasePropertyProxy.convertValueToBeSet
def convertValueToBeSet(self, obj, value)
Definition: PropertyProxy.py:376
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.getDefaultConfigurable
def getDefaultConfigurable(self, typeAndName, requester)
Definition: PropertyProxy.py:211
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy.arrayType
arrayType
Definition: PropertyProxy.py:319
GaudiKernel.PropertyProxy.PropertyProxy.__delete__
def __delete__(self, obj)
Definition: PropertyProxy.py:145
GaudiKernel.GaudiHandles
Definition: GaudiHandles.py:1
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.__get__
def __get__
Definition: PropertyProxy.py:172
GaudiKernel.DataObjectHandleBase.DataObjectHandleBase
Definition: DataObjectHandleBase.py:10
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy
Definition: PropertyProxy.py:312
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy.convertDefaultToBeSet
def convertDefaultToBeSet(self, obj, default)
Definition: PropertyProxy.py:328
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.isConfig
def isConfig(self, value)
Definition: PropertyProxy.py:206
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.isHandle
def isHandle(self, value)
Definition: PropertyProxy.py:201
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy.checkType
def checkType(self, obj, value)
Definition: PropertyProxy.py:322
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxy
Definition: PropertyProxy.py:307
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase._confTypeName
_confTypeName
Definition: PropertyProxy.py:168
GaudiKernel.PropertyProxy.PropertyProxy.descr
descr
Definition: PropertyProxy.py:65
GaudiKernel.PropertyProxy.PropertyProxy.getDefault
def getDefault(self)
Definition: PropertyProxy.py:75
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.convertValueToBeSet
def convertValueToBeSet(self, obj, value)
Definition: PropertyProxy.py:265
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase
Definition: PropertyProxy.py:152
GaudiKernel.PropertyProxy.PropertyProxy.__default
__default
Definition: PropertyProxy.py:73
GaudiKernel.PropertyProxy.PropertyProxy
Definition: PropertyProxy.py:62
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy.convertValueToBeSet
def convertValueToBeSet(self, obj, value)
Definition: PropertyProxy.py:338
GaudiKernel.PropertyProxy.DataObjectHandleBasePropertyProxy.__set__
def __set__(self, obj, value)
Definition: PropertyProxy.py:368
gaudirun.type
string type
Definition: gaudirun.py:151
GaudiKernel.PropertyProxy.DataObjectHandleBasePropertyProxy
Definition: PropertyProxy.py:347
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase._handleType
_handleType
Definition: PropertyProxy.py:167
GaudiKernel.PropertyProxy.PropertyProxy.default
default
Definition: PropertyProxy.py:78
GaudiKernel.PropertyProxy.DataObjectHandleBasePropertyProxy.__get__
def __get__
Definition: PropertyProxy.py:352
GaudiKernel.PropertyProxy.PropertyProxy.__init__
def __init__
Definition: PropertyProxy.py:63
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxy.__init__
def __init__(self, descr, docString, default)
Definition: PropertyProxy.py:308
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.__set__
def __set__(self, obj, value)
Definition: PropertyProxy.py:189
GaudiKernel.PropertyProxy.PropertyProxy.__doc__
__doc__
Definition: PropertyProxy.py:67
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.__init__
def __init__(self, descr, docString, default, handleType, allowedType)
Definition: PropertyProxy.py:155
GaudiKernel.PropertyProxy.GaudiHandleArrayPropertyProxy.__init__
def __init__(self, descr, docString, default)
Definition: PropertyProxy.py:313
GaudiKernel.PropertyProxy.PropertyProxy.__set__
def __set__(self, obj, value)
Definition: PropertyProxy.py:97
GaudiKernel.PropertyProxy.derives_from
def derives_from(derived, base)
Definition: PropertyProxy.py:20
GaudiKernel.PropertyProxy.PropertyProxyFactory
def PropertyProxyFactory(descr, doc, default)
Definition: PropertyProxy.py:385
GaudiKernel.DataObjectHandleBase
Definition: DataObjectHandleBase.py:1
GaudiKernel.PropertyProxy.DataObjectHandleBasePropertyProxy.__init__
def __init__(self, descr, docString, default)
Definition: PropertyProxy.py:349
GaudiKernel.PropertyProxy.PropertyProxy.fullPropertyName
def fullPropertyName(self, obj)
Definition: PropertyProxy.py:80
GaudiKernel.PropertyProxy.GaudiHandlePropertyProxyBase.convertDefaultToBeSet
def convertDefaultToBeSet(self, obj, default)
Definition: PropertyProxy.py:232
GaudiKernel.PropertyProxy._isCompatible
def _isCompatible(tp, value)
Definition: PropertyProxy.py:31
GaudiKernel.PropertyProxy.PropertyProxy.setDefault
def setDefault(self, value)
Definition: PropertyProxy.py:72