| The Gaudi Framework v29r0 (ff2e7097)

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