The Gaudi Framework  v36r1 (3e2fb5a8)
_configurables.py
Go to the documentation of this file.
1 
12 from __future__ import absolute_import
13 
14 import sys
15 
16 _GLOBAL_INSTANCES = False
17 
18 
19 def useGlobalInstances(enable):
20  '''
21  Enable or disable the global instances database.
22 
23  By default global instances are enabled.
24  '''
25  global _GLOBAL_INSTANCES
26  if enable == _GLOBAL_INSTANCES:
27  return
28  if not enable:
29  assert not Configurable.instances, \
30  'Configurable instances DB not empty, cannot be disabled'
31  _GLOBAL_INSTANCES = enable
32 
33 
34 class Property(object):
35  '''
36  Descriptor class to implement validation of Configurable properties.
37  '''
38 
39  def __init__(self, cpp_type, default, doc='undocumented', semantics=None):
40  from .semantics import getSemanticsFor
41  self.semantics = getSemanticsFor(semantics or cpp_type)
42  self.default = default
43  self.__doc__ = doc
44 
45  @property
46  def cpp_type(self):
47  return self.semantics.cpp_type
48 
49  @property
50  def name(self):
51  return self.semantics.name
52 
53  def __get__(self, instance, owner):
54  if (self.name not in instance._properties
55  and hasattr(self.semantics, 'default')):
56  instance._properties[self.name] = self.semantics.default(
57  self.default)
58  return self.semantics.load(
59  instance._properties.get(self.name, self.default))
60 
61  def __set__(self, instance, value):
62  instance._properties[self.name] = self.semantics.store(value)
63 
64  def __delete__(self, instance):
65  del instance._properties[self.name]
66 
67  def __set_name__(self, owner, name):
68  self.semantics.name = name
69 
70  def __is_set__(self, instance, owner):
71  try:
72  value = instance._properties[self.name]
73  return self.semantics.is_set(value)
74  except KeyError:
75  return False
76 
77  def __opt_value__(self, instance, owner):
78  return self.semantics.opt_value(
79  instance._properties.get(self.name, self.default))
80 
81  def __merge__(self, instance, owner, value):
82  '''
83  Return "merge" (according to the semantic) of the value
84  in this property and the incoming value.
85  '''
86  if not self.__is_set__(instance, owner):
87  return value
88  return self.semantics.merge(self.__get__(instance, owner), value)
89 
90 
92  '''
93  Metaclass for Configurables.
94  '''
95 
96  def __new__(cls, name, bases, namespace, **kwds):
97  props = {
98  key: namespace[key]
99  for key in namespace if isinstance(namespace[key], Property)
100  }
101  if props:
102  doc = namespace.get('__doc__', '').rstrip()
103  doc += '\n\nProperties\n----------\n'
104  doc += '\n'.join([
105  '- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n'.
106  format(name=n, p=props[n]) for n in props
107  ])
108  namespace['__doc__'] = doc
109  if sys.version_info < (3, 6): # pragma no cover
110  for n in props:
111  namespace[n].__set_name__(None, n)
112  namespace['_descriptors'] = props
113  slots = set(namespace.get('__slots__', []))
114  slots.update(['_properties', '_name'])
115  namespace['__slots__'] = tuple(slots)
116  result = type.__new__(cls, name, bases, namespace)
117  return result
118 
119 
120 def opt_repr(value):
121  '''
122  String representation of the value, such that it can be consumed be the
123  Gaudi option parsers.
124  '''
125  if hasattr(value, '__opt_repr__'):
126  return value.__opt_repr__()
127  return repr(value)
128 
129 
130 if sys.version_info >= (3, ): # pragma no cover
131  exec('class ConfigMetaHelper(metaclass=ConfigurableMeta):\n pass')
132 else: # pragma no cover
133 
134  class ConfigMetaHelper(object):
135  __metaclass__ = ConfigurableMeta
136 
137 
139  '''
140  Base class for all configurable instances.
141  '''
142  instances = {}
143 
144  def __init__(self, name=None, **kwargs):
145  self._name = None
146  self._properties = {}
147  if 'parent' in kwargs:
148  parent = kwargs.pop('parent')
149  if isinstance(parent,
150  basestring if sys.version_info[0] == 2 else str):
151  parent = self.instances[parent]
152  if not name:
153  raise TypeError('name is needed when a parent is specified')
154  name = '{}.{}'.format(parent.name, name)
155  if name:
156  self.name = name
157  elif not _GLOBAL_INSTANCES:
158  self.name = self.__cpp_type__
159  for key, value in kwargs.items():
160  setattr(self, key, value)
161 
162  @classmethod
163  def getInstance(cls, name):
164  return cls.instances.get(name) or cls(name)
165 
166  @property
167  def name(self):
168  if not self._name:
169  raise AttributeError('{!r} instance was not named yet'.format(
170  type(self).__name__))
171  return self._name
172 
173  @name.setter
174  def name(self, value):
175  if value == self._name:
176  return # it's already the name of the instance, nothing to do
177  if not isinstance(value, basestring
178  if sys.version_info[0] == 2 else str) or not value:
179  raise TypeError('expected string, got {} instead'.format(
180  type(value).__name__))
181  if _GLOBAL_INSTANCES:
182  if value in self.instances:
183  raise ValueError('name {!r} already used'.format(value))
184  if self._name in self.instances:
185  del self.instances[self._name]
186  self._name = value
187  self.instances[value] = self
188  else:
189  self._name = value
190 
191  @name.deleter
192  def name(self):
193  if _GLOBAL_INSTANCES:
194  # check if it was set
195  del self.instances[self.name]
196  self._name = None
197  else:
198  raise TypeError('name attribute cannot be deleted')
199 
200  def __repr__(self):
201  args = []
202  try:
203  args.append(repr(self.name))
204  except AttributeError:
205  pass # no name
206  args.extend(
207  '{}={!r}'.format(*item) for item in self._properties.items())
208  return '{}({})'.format(type(self).__name__, ', '.join(args))
209 
210  def __getstate__(self):
211  state = {'properties': self._properties}
212  try:
213  state['name'] = self.name
214  except AttributeError:
215  pass # no name
216  return state
217 
218  def __setstate__(self, state):
219  self._name = None
220  self.name = state.get('name')
221  self._properties = state['properties']
222 
223  def __opt_value__(self):
224  if self.__cpp_type__ == self.name:
225  return self.__cpp_type__
226  return '{}/{}'.format(self.__cpp_type__, self.name)
227 
228  def __opt_properties__(self, explicit_defaults=False):
229  name = self.name
230  out = {}
231  for p in self._descriptors.values():
232  if explicit_defaults or p.__is_set__(self, type(self)):
233  out['.'.join([name, p.name])] = opt_repr(
234  p.__opt_value__(self, type(self)))
235  return out
236 
237  def is_property_set(self, propname):
238  return self._descriptors[propname].__is_set__(self, type(self))
239 
240  @classmethod
241  def getGaudiType(cls):
242  return cls.__component_type__
243 
244  @classmethod
245  def getType(cls):
246  return cls.__cpp_type__
247 
248  def getName(self):
249  return self.name
250 
251  def getFullJobOptName(self):
252  return "{}/{}".format(self.__cpp_type__, self.name)
253 
254  def toStringProperty(self):
255  return "{}/{}".format(self.__cpp_type__, self.name)
256 
257  @classmethod
259  return {k: v.default for k, v in cls._descriptors.items()}
260 
261  @classmethod
262  def getDefaultProperty(cls, name):
263  return cls._descriptors[name].default
264 
265  def merge(self, other):
266  '''
267  Merge the properties of the other instance into the current one.
268 
269  The two instances have to be of the same type, have the same name
270  (or both unnamed) and the settings must be mergable (according to
271  their semantics).
272  '''
273  if type(self) is not type(other):
274  raise TypeError(
275  'cannot merge instance of {} into an instance of {}'.format(
276  type(other).__name__,
277  type(self).__name__))
278  if hasattr(self, 'name') != hasattr(other, 'name'):
279  raise ValueError(
280  'cannot merge a named configurable with an unnamed one')
281  if hasattr(self, 'name') and (self.name != other.name):
282  raise ValueError(
283  'cannot merge configurables with different names ({} and {})'.
284  format(self.name, other.name))
285 
286  for name in other._descriptors:
287  if not other.is_property_set(name):
288  continue
289  try:
290  setattr(
291  self, name, self._descriptors[name].__merge__(
292  self, type(self), getattr(other, name)))
293  except ValueError as err:
294  raise ValueError(
295  'conflicting settings for property {} of {}: {}'.format(
296  name, self.name
297  if hasattr(self, 'name') else type(self).__name__,
298  str(err)))
299 
300  return self
301 
302 
303 def makeConfigurableClass(name, **namespace):
304  '''
305  Create a Configurable specialization.
306  '''
307  properties = namespace.pop('properties', {})
308  namespace.update(
309  {pname: Property(*pargs)
310  for pname, pargs in properties.items()})
311 
312  return type(name, (Configurable, ), namespace)
313 
314 
315 def all_options(explicit_defaults=False):
316  '''
317  Return a dictionary with all explicitly set options, or with also the
318  defaults if explicit_defaults is set to True.
319  '''
320  opts = {}
321  for c in Configurable.instances.values():
322  opts.update(c.__opt_properties__(explicit_defaults))
323  return opts
GaudiConfig2._configurables.Configurable.getName
def getName(self)
Definition: _configurables.py:248
GaudiConfig2._configurables.Property.__doc__
__doc__
Definition: _configurables.py:43
GaudiConfig2._configurables.Property.default
default
Definition: _configurables.py:42
GaudiConfig2._configurables.ConfigurableMeta
Definition: _configurables.py:91
GaudiConfig2._configurables.Configurable
Definition: _configurables.py:138
GaudiConfig2._configurables.Configurable.is_property_set
def is_property_set(self, propname)
Definition: _configurables.py:237
GaudiConfig2._configurables.Configurable.__opt_properties__
def __opt_properties__(self, explicit_defaults=False)
Definition: _configurables.py:228
GaudiConfig2._configurables.Configurable.__cpp_type__
__cpp_type__
Definition: _configurables.py:224
GaudiConfig2._configurables.Configurable.getDefaultProperty
def getDefaultProperty(cls, name)
Definition: _configurables.py:262
GaudiConfig2._configurables.Property.cpp_type
def cpp_type(self)
Definition: _configurables.py:46
GaudiConfig2._configurables.Property.__is_set__
def __is_set__(self, instance, owner)
Definition: _configurables.py:70
GaudiConfig2._configurables.Configurable.getGaudiType
def getGaudiType(cls)
Definition: _configurables.py:241
GaudiConfig2._configurables.Property.__merge__
def __merge__(self, instance, owner, value)
Definition: _configurables.py:81
GaudiConfig2._configurables.Property.__init__
def __init__(self, cpp_type, default, doc='undocumented', semantics=None)
Definition: _configurables.py:39
GaudiConfig2._configurables.Configurable.__init__
def __init__(self, name=None, **kwargs)
Definition: _configurables.py:144
GaudiConfig2._configurables.Configurable.__repr__
def __repr__(self)
Definition: _configurables.py:200
GaudiConfig2._configurables.Property.name
def name(self)
Definition: _configurables.py:50
GaudiConfig2.semantics.getSemanticsFor
def getSemanticsFor(cpp_type, name=None)
Definition: semantics.py:450
GaudiConfig2._configurables.Property.__set__
def __set__(self, instance, value)
Definition: _configurables.py:61
GaudiConfig2._configurables.Configurable.getFullJobOptName
def getFullJobOptName(self)
Definition: _configurables.py:251
GaudiConfig2._configurables.ConfigMetaHelper
Definition: _configurables.py:134
Gaudi::Functional::details::get
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
Definition: FunctionalDetails.h:391
GaudiConfig2._configurables.Configurable.merge
def merge(self, other)
Definition: _configurables.py:265
GaudiConfig2._configurables.Configurable.name
name
Definition: _configurables.py:156
GaudiConfig2._configurables.opt_repr
def opt_repr(value)
Definition: _configurables.py:120
GaudiConfig2._configurables.all_options
def all_options(explicit_defaults=False)
Definition: _configurables.py:315
GaudiConfig2._configurables.Configurable.__getstate__
def __getstate__(self)
Definition: _configurables.py:210
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
GaudiConfig2._configurables.Configurable.toStringProperty
def toStringProperty(self)
Definition: _configurables.py:254
GaudiConfig2._configurables.Configurable.getDefaultProperties
def getDefaultProperties(cls)
Definition: _configurables.py:258
gaudirun.type
type
Definition: gaudirun.py:154
merge
int merge(const char *target, const char *source, bool fixup=false, bool dbg=true)
Definition: merge.C:430
GaudiConfig2._configurables.Configurable._properties
_properties
Definition: _configurables.py:146
GaudiConfig2._configurables.Property.__delete__
def __delete__(self, instance)
Definition: _configurables.py:64
GaudiConfig2._configurables.Configurable.getType
def getType(cls)
Definition: _configurables.py:245
GaudiConfig2._configurables.Property.__set_name__
def __set_name__(self, owner, name)
Definition: _configurables.py:67
GaudiConfig2._configurables.ConfigurableMeta.__new__
def __new__(cls, name, bases, namespace, **kwds)
Definition: _configurables.py:96
GaudiConfig2._configurables.Property.semantics
semantics
Definition: _configurables.py:41
GaudiConfig2._configurables.Property
Definition: _configurables.py:34
GaudiConfig2._configurables.Property.__opt_value__
def __opt_value__(self, instance, owner)
Definition: _configurables.py:77
Gaudi.CommonGaudiConfigurables.cls
cls
Definition: CommonGaudiConfigurables.py:35
GaudiConfig2._configurables.makeConfigurableClass
def makeConfigurableClass(name, **namespace)
Definition: _configurables.py:303
GaudiConfig2._configurables.Configurable.__opt_value__
def __opt_value__(self)
Definition: _configurables.py:223
GaudiConfig2._configurables.useGlobalInstances
def useGlobalInstances(enable)
Definition: _configurables.py:19
GaudiConfig2._configurables.Property.__get__
def __get__(self, instance, owner)
Definition: _configurables.py:53
GaudiConfig2._configurables.Configurable._name
_name
Definition: _configurables.py:145
GaudiConfig2._configurables.Configurable.getInstance
def getInstance(cls, name)
Definition: _configurables.py:163
GaudiConfig2._configurables.Configurable.instances
dictionary instances
Definition: _configurables.py:142
GaudiConfig2._configurables.Configurable.__setstate__
def __setstate__(self, state)
Definition: _configurables.py:218
GaudiPython.Pythonizations.items
items
Definition: Pythonizations.py:526