Loading [MathJax]/jax/output/HTML-CSS/config.js
The Gaudi Framework  v36r16 (ea80daf8)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
_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 (
30  not Configurable.instances
31  ), "Configurable instances DB not empty, cannot be disabled"
32  _GLOBAL_INSTANCES = enable
33 
34 
35 class Property(object):
36  """
37  Descriptor class to implement validation of Configurable properties.
38  """
39 
40  def __init__(self, cpp_type, default, doc="undocumented", semantics=None):
41  from .semantics import getSemanticsFor
42 
43  self.semantics = getSemanticsFor(semantics or cpp_type)
44  self.default = default
45  self.__doc__ = doc
46 
47  @property
48  def cpp_type(self):
49  return self.semantics.cpp_type
50 
51  @property
52  def name(self):
53  return self.semantics.name
54 
55  def __get__(self, instance, owner):
56  if self.name not in instance._properties and hasattr(self.semantics, "default"):
57  instance._properties[self.name] = self.semantics.default(self.default)
58  return self.semantics.load(instance._properties.get(self.name, self.default))
59 
60  def __set__(self, instance, value):
61  instance._properties[self.name] = self.semantics.store(value)
62 
63  def __delete__(self, instance):
64  del instance._properties[self.name]
65 
66  def __set_name__(self, owner, name):
67  self.semantics.name = name
68 
69  def __is_set__(self, instance, owner):
70  try:
71  value = instance._properties[self.name]
72  return self.semantics.is_set(value)
73  except KeyError:
74  return False
75 
76  def __opt_value__(self, instance, owner):
77  return self.semantics.opt_value(
78  instance._properties.get(self.name, self.default)
79  )
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
100  if isinstance(namespace[key], Property)
101  }
102  if props:
103  doc = namespace.get("__doc__", "").rstrip()
104  doc += "\n\nProperties\n----------\n"
105  doc += "\n".join(
106  [
107  "- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n".format(
108  name=n, p=props[n]
109  )
110  for n in props
111  ]
112  )
113  namespace["__doc__"] = doc
114  if sys.version_info < (3, 6): # pragma no cover
115  for n in props:
116  namespace[n].__set_name__(None, n)
117  namespace["_descriptors"] = props
118  slots = set(namespace.get("__slots__", []))
119  slots.update(["_properties", "_name"])
120  namespace["__slots__"] = tuple(slots)
121  result = type.__new__(cls, name, bases, namespace)
122  return result
123 
124 
125 def opt_repr(value):
126  """
127  String representation of the value, such that it can be consumed be the
128  Gaudi option parsers.
129  """
130  if hasattr(value, "__opt_repr__"):
131  return value.__opt_repr__()
132  elif isinstance(value, str):
133  return '"{}"'.format(value.replace('"', '\\"'))
134  return repr(value)
135 
136 
137 if sys.version_info >= (3,): # pragma no cover
138  exec("class ConfigMetaHelper(metaclass=ConfigurableMeta):\n pass")
139 else: # pragma no cover
140 
141  class ConfigMetaHelper(object):
142  __metaclass__ = ConfigurableMeta
143 
144 
146  """
147  Base class for all configurable instances.
148  """
149 
150  instances = {}
151 
152  def __init__(self, name=None, **kwargs):
153  self._name = None
154  self._properties = {}
155  if "parent" in kwargs:
156  parent = kwargs.pop("parent")
157  if isinstance(parent, str):
158  parent = self.instances[parent]
159  if not name:
160  raise TypeError("name is needed when a parent is specified")
161  name = "{}.{}".format(parent.name, name)
162  if name:
163  self.name = name
164  elif not _GLOBAL_INSTANCES:
165  self.name = self.__cpp_type__
166  for key, value in kwargs.items():
167  setattr(self, key, value)
168 
169  @classmethod
170  def getInstance(cls, name):
171  return cls.instances.get(name) or cls(name)
172 
173  @property
174  def name(self):
175  if not self._name:
176  raise AttributeError(
177  "{!r} instance was not named yet".format(type(self).__name__)
178  )
179  return self._name
180 
181  @name.setter
182  def name(self, value):
183  if value == self._name:
184  return # it's already the name of the instance, nothing to do
185  if not isinstance(value, str) or not value:
186  raise TypeError(
187  "expected string, got {} instead".format(type(value).__name__)
188  )
189  if _GLOBAL_INSTANCES:
190  if value in self.instances:
191  raise ValueError("name {!r} already used".format(value))
192  if self._name in self.instances:
193  del self.instances[self._name]
194  self._name = value
195  self.instances[value] = self
196  else:
197  self._name = value
198 
199  @name.deleter
200  def name(self):
201  if _GLOBAL_INSTANCES:
202  # check if it was set
203  del self.instances[self.name]
204  self._name = None
205  else:
206  raise TypeError("name attribute cannot be deleted")
207 
208  def __repr__(self):
209  args = []
210  try:
211  args.append(repr(self.name))
212  except AttributeError:
213  pass # no name
214  args.extend("{}={!r}".format(*item) for item in self._properties.items())
215  return "{}({})".format(type(self).__name__, ", ".join(args))
216 
217  def __getstate__(self):
218  state = {"properties": self._properties}
219  try:
220  state["name"] = self.name
221  except AttributeError:
222  pass # no name
223  return state
224 
225  def __setstate__(self, state):
226  self._name = None
227  self.name = state.get("name")
228  self._properties = state["properties"]
229 
230  def __opt_value__(self):
231  if self.__cpp_type__ == self.name:
232  return self.__cpp_type__
233  return "{}/{}".format(self.__cpp_type__, self.name)
234 
235  def __opt_properties__(self, explicit_defaults=False):
236  name = self.name
237  out = {}
238  for p in self._descriptors.values():
239  if explicit_defaults or p.__is_set__(self, type(self)):
240  out[".".join([name, p.name])] = opt_repr(
241  p.__opt_value__(self, type(self))
242  )
243  return out
244 
245  def is_property_set(self, propname):
246  return self._descriptors[propname].__is_set__(self, type(self))
247 
248  @classmethod
249  def getGaudiType(cls):
250  return cls.__component_type__
251 
252  @classmethod
253  def getType(cls):
254  return cls.__cpp_type__
255 
256  def getName(self):
257  return self.name
258 
259  def getFullJobOptName(self):
260  return "{}/{}".format(self.__cpp_type__, self.name)
261 
262  def toStringProperty(self):
263  return "{}/{}".format(self.__cpp_type__, self.name)
264 
265  @classmethod
267  return {k: v.default for k, v in cls._descriptors.items()}
268 
269  @classmethod
270  def getDefaultProperty(cls, name):
271  return cls._descriptors[name].default
272 
273  def clone(self, newname=None):
274  """Clone instance with all its properties."""
275  return self.__class__(newname, **self._properties)
276 
277  def merge(self, other):
278  """
279  Merge the properties of the other instance into the current one.
280 
281  The two instances have to be of the same type, have the same name
282  (or both unnamed) and the settings must be mergable (according to
283  their semantics).
284  """
285  if self is other:
286  return self
287  if type(self) is not type(other):
288  raise TypeError(
289  "cannot merge instance of {} into an instance of {}".format(
290  type(other).__name__, type(self).__name__
291  )
292  )
293  if hasattr(self, "name") != hasattr(other, "name"):
294  raise ValueError("cannot merge a named configurable with an unnamed one")
295  if hasattr(self, "name") and (self.name != other.name):
296  raise ValueError(
297  "cannot merge configurables with different names ({} and {})".format(
298  self.name, other.name
299  )
300  )
301 
302  for name in other._properties:
303  if (
304  name in self._properties
305  and self._properties[name] == other._properties[name]
306  ):
307  continue
308  try:
309  setattr(
310  self,
311  name,
312  self._descriptors[name].__merge__(
313  self, type(self), getattr(other, name)
314  ),
315  )
316  except ValueError as err:
317  raise ValueError(
318  "conflicting settings for property {} of {}: {}".format(
319  name,
320  self.name if hasattr(self, "name") else type(self).__name__,
321  str(err),
322  )
323  )
324 
325  return self
326 
327 
328 def makeConfigurableClass(name, **namespace):
329  """
330  Create a Configurable specialization.
331  """
332  properties = namespace.pop("properties", {})
333  namespace.update({pname: Property(*pargs) for pname, pargs in properties.items()})
334 
335  return type(name, (Configurable,), namespace)
336 
337 
338 def all_options(explicit_defaults=False):
339  """
340  Return a dictionary with all explicitly set options, or with also the
341  defaults if explicit_defaults is set to True.
342  """
343  opts = {}
344  for c in Configurable.instances.values():
345  opts.update(c.__opt_properties__(explicit_defaults))
346  return opts
GaudiConfig2._configurables.Configurable.getName
def getName(self)
Definition: _configurables.py:256
GaudiConfig2._configurables.Property.__doc__
__doc__
Definition: _configurables.py:45
GaudiConfig2._configurables.Property.default
default
Definition: _configurables.py:44
GaudiConfig2._configurables.ConfigurableMeta
Definition: _configurables.py:91
GaudiConfig2._configurables.Configurable
Definition: _configurables.py:145
GaudiConfig2._configurables.Property.__init__
def __init__(self, cpp_type, default, doc="undocumented", semantics=None)
Definition: _configurables.py:40
GaudiConfig2._configurables.Configurable.is_property_set
def is_property_set(self, propname)
Definition: _configurables.py:245
GaudiConfig2._configurables.Configurable.__opt_properties__
def __opt_properties__(self, explicit_defaults=False)
Definition: _configurables.py:235
GaudiConfig2._configurables.Configurable.__cpp_type__
__cpp_type__
Definition: _configurables.py:231
GaudiConfig2._configurables.Configurable.getDefaultProperty
def getDefaultProperty(cls, name)
Definition: _configurables.py:270
GaudiConfig2._configurables.Configurable.instances
instances
Definition: _configurables.py:150
GaudiConfig2._configurables.Property.cpp_type
def cpp_type(self)
Definition: _configurables.py:48
GaudiConfig2._configurables.Property.__is_set__
def __is_set__(self, instance, owner)
Definition: _configurables.py:69
GaudiConfig2._configurables.Configurable.getGaudiType
def getGaudiType(cls)
Definition: _configurables.py:249
GaudiConfig2._configurables.Configurable.clone
def clone(self, newname=None)
Definition: _configurables.py:273
GaudiConfig2._configurables.Property.__merge__
def __merge__(self, instance, owner, value)
Definition: _configurables.py:81
GaudiConfig2._configurables.Configurable.__init__
def __init__(self, name=None, **kwargs)
Definition: _configurables.py:152
GaudiConfig2._configurables.Configurable.__repr__
def __repr__(self)
Definition: _configurables.py:208
GaudiConfig2._configurables.Property.name
def name(self)
Definition: _configurables.py:52
GaudiConfig2.semantics.getSemanticsFor
def getSemanticsFor(cpp_type, name=None)
Definition: semantics.py:507
GaudiConfig2._configurables.Property.__set__
def __set__(self, instance, value)
Definition: _configurables.py:60
GaudiConfig2._configurables.Configurable.getFullJobOptName
def getFullJobOptName(self)
Definition: _configurables.py:259
GaudiConfig2._configurables.ConfigMetaHelper
Definition: _configurables.py:141
Gaudi::Functional::details::get
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
Definition: FunctionalDetails.h:444
GaudiConfig2._configurables.Configurable.merge
def merge(self, other)
Definition: _configurables.py:277
GaudiConfig2._configurables.Configurable.name
name
Definition: _configurables.py:163
GaudiConfig2._configurables.opt_repr
def opt_repr(value)
Definition: _configurables.py:125
GaudiConfig2._configurables.all_options
def all_options(explicit_defaults=False)
Definition: _configurables.py:338
GaudiConfig2._configurables.Configurable.__getstate__
def __getstate__(self)
Definition: _configurables.py:217
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:262
GaudiConfig2._configurables.Configurable.getDefaultProperties
def getDefaultProperties(cls)
Definition: _configurables.py:266
gaudirun.type
type
Definition: gaudirun.py:162
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:154
GaudiConfig2._configurables.Property.__delete__
def __delete__(self, instance)
Definition: _configurables.py:63
GaudiConfig2._configurables.Configurable.getType
def getType(cls)
Definition: _configurables.py:253
GaudiConfig2._configurables.Property.__set_name__
def __set_name__(self, owner, name)
Definition: _configurables.py:66
GaudiConfig2._configurables.ConfigurableMeta.__new__
def __new__(cls, name, bases, namespace, **kwds)
Definition: _configurables.py:96
GaudiConfig2._configurables.Property.semantics
semantics
Definition: _configurables.py:43
GaudiConfig2._configurables.Property
Definition: _configurables.py:35
GaudiConfig2._configurables.Property.__opt_value__
def __opt_value__(self, instance, owner)
Definition: _configurables.py:76
Gaudi.CommonGaudiConfigurables.cls
cls
Definition: CommonGaudiConfigurables.py:44
GaudiConfig2._configurables.makeConfigurableClass
def makeConfigurableClass(name, **namespace)
Definition: _configurables.py:328
GaudiConfig2._configurables.Configurable.__opt_value__
def __opt_value__(self)
Definition: _configurables.py:230
GaudiConfig2._configurables.useGlobalInstances
def useGlobalInstances(enable)
Definition: _configurables.py:19
GaudiConfig2._configurables.Property.__get__
def __get__(self, instance, owner)
Definition: _configurables.py:55
GaudiConfig2._configurables.Configurable._name
_name
Definition: _configurables.py:153
GaudiConfig2._configurables.Configurable.getInstance
def getInstance(cls, name)
Definition: _configurables.py:170
GaudiConfig2._configurables.Configurable.__setstate__
def __setstate__(self, state)
Definition: _configurables.py:225
GaudiPython.Pythonizations.items
items
Definition: Pythonizations.py:546