The Gaudi Framework  v36r3 (83a1ddab)
semantics.py
Go to the documentation of this file.
1 
11 from __future__ import absolute_import
12 
13 import logging
14 import re
15 import sys
16 
17 try:
18  from collections.abc import MutableMapping, MutableSequence
19 except ImportError: # pragma no cover
20  # Python 2 version
21  from collections import MutableMapping, MutableSequence
22 
23 if sys.version_info >= (3,): # pragma no cover
24  basestring = str
25 
26 _log = logging.getLogger(__name__)
27 is_64bits = sys.maxsize > 2 ** 32
28 
29 
30 class PropertySemantics(object):
31  """
32  Basic property semantics implementation, with no validation/transformation.
33  """
34 
35  __handled_types__ = (re.compile(r".*"),)
36 
37  def __init__(self, cpp_type, name=None):
38  self.name = None
39  self.cpp_type = cpp_type
40 
41  @property
42  def cpp_type(self):
43  return self._cpp_type
44 
45  @cpp_type.setter
46  def cpp_type(self, value):
47  if not any(
48  h.match(value) if hasattr(h, "match") else h == value
49  for h in self.__handled_types__
50  ):
51  raise TypeError("C++ type {!r} not supported".format(value))
52  self._cpp_type = value
53 
54  def load(self, value):
55  """
56  Transformation for data when reading the property.
57  """
58  return value
59 
60  def store(self, value):
61  """
62  Validation/transformation of the data to be stored.
63  """
64  return value
65 
66  def is_set(self, value):
67  """
68  Allow overriding the definition of "is set" if we need helper types.
69  """
70  return True
71 
72  def opt_value(self, value):
73  """
74  Option string version of value.
75  """
76  if hasattr(value, "__opt_value__"):
77  return value.__opt_value__()
78  return value
79 
80  def merge(self, a, b):
81  """
82  "Merge" two values.
83 
84  Used when merging two Configurable instances, by default just ensure
85  the two values do not conflict, but it can be overridden in
86  derived semantics to, for example, append to the two lists.
87  """
88  if self.store(a) != self.store(b):
89  raise ValueError("cannot merge values %r and %r" % (a, b))
90  return a
91 
92 
93 DefaultSemantics = PropertySemantics
94 
95 
97  __handled_types__ = ("std::string",)
98 
99  def store(self, value):
100  if not isinstance(value, basestring):
101  raise ValueError("cannot set property {} to {!r}".format(self.name, value))
102  return value
103 
104 
106  __handled_types__ = ("bool",)
107 
108  def store(self, value):
109  return bool(value)
110 
111 
113  __handled_types__ = ("float", "double")
114 
115  def store(self, value):
116  from numbers import Number
117 
118  if not isinstance(value, Number):
119  raise TypeError(
120  "number expected, got {!r} in assignemnt to {}".format(value, self.name)
121  )
122  return float(value)
123 
124 
126  # dictionary generated with tools/print_limits.cpp
127  INT_RANGES = {
128  "signed char": (-128, 127),
129  "short": (-32768, 32767),
130  "int": (-2147483648, 2147483647),
131  "long": (
132  (-9223372036854775808, 9223372036854775807)
133  if is_64bits
134  else (-2147483648, 2147483647)
135  ),
136  "long long": (-9223372036854775808, 9223372036854775807),
137  "unsigned char": (0, 255),
138  "unsigned short": (0, 65535),
139  "unsigned int": (0, 4294967295),
140  "unsigned long": (0, 18446744073709551615 if is_64bits else 4294967295),
141  "unsigned long long": (0, 18446744073709551615),
142  }
143 
144  __handled_types__ = tuple(INT_RANGES)
145 
146  def store(self, value):
147  from numbers import Number
148 
149  if not isinstance(value, Number):
150  raise TypeError(
151  "number expected, got {!r} in assignemnt to {}".format(value, self.name)
152  )
153  v = int(value)
154  if v != value:
155  _log.warning("converted %s to %d in assignment to %s", value, v, self.name)
156  min_value, max_value = self.INT_RANGES[self.cpp_type]
157  if v < min_value or v > max_value:
158  raise ValueError(
159  "value {} outside limits for {!r} {}".format(
160  v, self.cpp_type, self.INT_RANGES[self.cpp_type]
161  )
162  )
163  return v
164 
165 
166 _IDENTIFIER_RE = r"[a-zA-Z_][a-zA-Z0-9_]*"
167 _NS_IDENT_RE = r"{ident}(::{ident})*".format(ident=_IDENTIFIER_RE)
168 _COMMA_SEPARATION_RE = r"{exp}(,{exp})*"
169 
170 
172  __handled_types__ = (
173  "Algorithm",
174  "Auditor",
175  re.compile(
176  r"AlgTool(:{})?$".format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
177  ),
178  re.compile(
179  r"Service(:{})?$".format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
180  ),
181  )
182 
183  def __init__(self, cpp_type, name=None):
184  super(ComponentSemantics, self).__init__(cpp_type, name)
185  if ":" in cpp_type:
186  self.cpp_type, self.interfaces = cpp_type.split(":", 1)
187  self.interfaces = set(self.interfaces.split(","))
188  else:
189  self.cpp_type = cpp_type
190  self.interfaces = set()
191 
192  def store(self, value):
193  from . import Configurable, Configurables
194 
195  if isinstance(value, Configurable):
196  value.name # make sure the configurable has a name
197  elif isinstance(value, basestring):
198  # try to map the sring to an existing Configurable
199  if value in Configurable.instances:
200  value = Configurable.instances[value]
201  else:
202  # or create one from type and name
203  if "/" in value:
204  t, n = value.split("/")
205  else:
206  t = n = value
207  value = Configurables.getByType(t).getInstance(n)
208  else:
209  raise TypeError(
210  "cannot assign {!r} to {!r}, requested string or {!r}".format(
211  value, self.name, self.cpp_type
212  )
213  )
214  if value.__component_type__ != self.cpp_type:
215  raise TypeError(
216  "wrong type for {!r}: expected {!r}, got {!r}".format(
217  self.name, self.cpp_type, value.__component_type__
218  )
219  )
220  try:
221  # if no interface is declared we cannot check
222  if value.__interfaces__:
223  if not self.interfaces.issubset(value.__interfaces__):
224  raise TypeError(
225  "wrong interfaces for {!r}: required {}".format(
226  self.name, list(self.interfaces)
227  )
228  )
229  except AttributeError:
230  pass # no interfaces declared by the configrable, cannot check
231  return value
232 
233  def default(self, value):
234  return self.store(value)
235 
236 
237 def extract_template_args(cpp_type):
238  """
239  Return an iterator over the list of template arguments in a C++ type
240  string.
241 
242  >>> t = 'map<string, vector<int, allocator<int> >, allocator<v<i>, a<i>> >'
243  >>> list(extract_template_args(t))
244  ['string', 'vector<int, allocator<int> >', 'allocator<v<i>, a<i>>']
245  >>> list(extract_template_args('int'))
246  []
247  """
248  template_level = 0
249  arg_start = -1
250  for p, c in enumerate(cpp_type):
251  if c == ",":
252  if template_level == 1:
253  yield cpp_type[arg_start:p].strip()
254  arg_start = p + 1
255  elif c == "<":
256  template_level += 1
257  if template_level == 1:
258  arg_start = p + 1
259  elif c == ">":
260  template_level -= 1
261  if template_level == 0:
262  yield cpp_type[arg_start:p].strip()
263 
264 
265 class _ListHelper(MutableSequence):
266  def __init__(self, semantics):
267  self.value_semantics = semantics
268  self.default = None
269  self._data = []
270  self.is_dirty = False
271 
272  @property
273  def data(self):
274  return self._data if self.is_dirty else self.default
275 
276  def __len__(self):
277  return len(self.data)
278 
279  def __getitem__(self, key):
280  return self.value_semantics.load(self.data.__getitem__(key))
281 
282  def __setitem__(self, key, value):
283  self.is_dirty = True
284  self.data.__setitem__(key, self.value_semantics.store(value))
285 
286  def __delitem__(self, key):
287  if not self.is_dirty:
288  raise RuntimeError("cannot remove elements from the default value")
289  self.data.__delitem__(key)
290 
291  def __eq__(self, other):
292  return self.data == other.data
293 
294  def __ne__(self, other):
295  return self.data != other.data
296 
297  def insert(self, key, value):
298  self.is_dirty = True
299  self.data.insert(key, self.value_semantics.store(value))
300 
301  def append(self, value):
302  self.is_dirty = True
303  self.data.append(self.value_semantics.store(value))
304 
305  def extend(self, iterable):
306  self.is_dirty = True
307  self.data.extend(self.value_semantics.store(value) for value in iterable)
308 
309  def opt_value(self):
310  return [self.value_semantics.opt_value(item) for item in self.data]
311 
312  def __repr__(self):
313  return repr(self.data)
314 
315 
317  __handled_types__ = (re.compile(r"(std::)?(vector|list)<.*>$"),)
318 
319  def __init__(self, cpp_type, name=None, valueSem=None):
320  super(SequenceSemantics, self).__init__(cpp_type, name)
321  self.value_semantics = valueSem or getSemanticsFor(
322  list(extract_template_args(cpp_type))[0]
323  )
324 
325  def store(self, value):
326  new_value = _ListHelper(self.value_semantics)
327  new_value.extend(value)
328  return new_value
329 
330  def default(self, value):
331  new_value = _ListHelper(self.value_semantics)
332  new_value.default = value
333  return new_value
334 
335  def opt_value(self, value):
336  """
337  Option string version of value.
338  """
339  if not isinstance(value, _ListHelper):
340  value = self.default(value)
341  return value.opt_value()
342 
343 
345  """
346  Extend the sequence-semantics with a merge-method to behave like a
347  OrderedSet: Values are unique but the order is maintained.
348  Use 'OrderedSet<T>' as fifth parameter of the Gaudi::Property<T> constructor
349  to invoke this merging method.
350  """
351 
352  __handled_types__ = (re.compile(r"^OrderedSet<.*>$"),)
353 
354  def __init__(self, cpp_type, name=None):
355  super(OrderedSetSemantics, self).__init__(cpp_type, name)
356 
357  def merge(self, bb, aa):
358  for b in bb:
359  if b not in aa:
360  aa.append(b)
361  return aa
362 
363 
364 class _DictHelper(MutableMapping):
365  def __init__(self, key_semantics, value_semantics):
366  self.key_semantics = key_semantics
367  self.value_semantics = value_semantics
368  self.default = None
369  self._data = {}
370  self.is_dirty = False
371 
372  @property
373  def data(self):
374  return self._data if self.is_dirty else self.default
375 
376  def __len__(self):
377  return len(self.data)
378 
379  def __getitem__(self, key):
380  return self.value_semantics.load(
381  self.data.__getitem__(self.key_semantics.store(key))
382  )
383 
384  def __setitem__(self, key, value):
385  self.is_dirty = True
386  self.data.__setitem__(
387  self.key_semantics.store(key), self.value_semantics.store(value)
388  )
389 
390  def __delitem__(self, key):
391  if not self.is_dirty:
392  raise RuntimeError("cannot remove elements from the default value")
393  self.data.__delitem__(self.key_semantics.store(key))
394 
395  def __iter__(self):
396  for key in self.data:
397  yield self.key_semantics.load(key)
398 
399  def keys(self):
400  return list(self)
401 
402  def items(self):
403  for key, value in self.data.items():
404  yield (self.key_semantics.load(key), self.value_semantics.load(value))
405 
406  def values(self):
407  for value in self.data.values():
408  yield self.value_semantics.load(value)
409 
410  def __contains__(self, key):
411  return self.key_semantics.store(key) in self.data
412 
413  def get(self, key, default=None):
414  key = self.key_semantics.store(key)
415  if key in self.data:
416  return self.value_semantics.load(self.data[key])
417  return default
418 
419  # __contains__, , get, __eq__, __ne__
420  # popitem, clear, setdefault
421 
422  def update(self, otherMap):
423  self.is_dirty = True
424  for key, value in otherMap.items():
425  self.data[self.key_semantics.store(key)] = self.value_semantics.store(value)
426 
427  def opt_value(self):
428  return {
429  self.key_semantics.opt_value(key): self.value_semantics.opt_value(value)
430  for key, value in self.data.items()
431  }
432 
433  def __repr__(self):
434  return repr(self.data)
435 
436 
438  __handled_types__ = (re.compile(r"(std::)?(unordered_)?map<.*>$"),)
439 
440  def __init__(self, cpp_type, name=None):
441  super(MappingSemantics, self).__init__(cpp_type, name)
442  template_args = list(extract_template_args(cpp_type))
443  self.key_semantics = getSemanticsFor(template_args[0])
444  self.value_semantics = getSemanticsFor(template_args[1])
445 
446  def store(self, value):
447  new_value = _DictHelper(self.key_semantics, self.value_semantics)
448  new_value.update(value)
449  return new_value
450 
451  def default(self, value):
452  new_value = _DictHelper(self.key_semantics, self.value_semantics)
453  new_value.default = value
454  return new_value
455 
456  def opt_value(self, value):
457  """
458  Option string version of value.
459  """
460  if not isinstance(value, _DictHelper):
461  value = self.default(value)
462  return value.opt_value()
463 
464 
465 SEMANTICS = [
466  c
467  for c in globals().values()
468  if isinstance(c, type)
469  and issubclass(c, PropertySemantics)
470  and c is not PropertySemantics
471 ]
472 
473 
474 def getSemanticsFor(cpp_type, name=None):
475  for semantics in SEMANTICS:
476  try:
477  return semantics(cpp_type, name)
478  except TypeError:
479  pass
480  return DefaultSemantics(cpp_type, name)
GaudiConfig2.semantics.OrderedSetSemantics.__init__
def __init__(self, cpp_type, name=None)
Definition: semantics.py:354
GaudiConfig2.semantics.ComponentSemantics.interfaces
interfaces
Definition: semantics.py:186
GaudiConfig2.semantics.SequenceSemantics.default
def default(self, value)
Definition: semantics.py:330
GaudiConfig2.semantics.MappingSemantics.store
def store(self, value)
Definition: semantics.py:446
GaudiConfig2.semantics.PropertySemantics._cpp_type
_cpp_type
Definition: semantics.py:52
GaudiConfig2.semantics.IntSemantics.store
def store(self, value)
Definition: semantics.py:146
GaudiConfig2.semantics._DictHelper.__delitem__
def __delitem__(self, key)
Definition: semantics.py:390
GaudiConfig2.semantics._ListHelper.__repr__
def __repr__(self)
Definition: semantics.py:312
GaudiConfig2.semantics.PropertySemantics.cpp_type
cpp_type
Definition: semantics.py:39
GaudiConfig2.semantics._DictHelper.__contains__
def __contains__(self, key)
Definition: semantics.py:410
GaudiConfig2.semantics.ComponentSemantics.store
def store(self, value)
Definition: semantics.py:192
GaudiConfig2.semantics.PropertySemantics.is_set
def is_set(self, value)
Definition: semantics.py:66
GaudiConfig2.semantics.PropertySemantics.load
def load(self, value)
Definition: semantics.py:54
GaudiConfig2.semantics.IntSemantics
Definition: semantics.py:125
GaudiConfig2.semantics._DictHelper.get
def get(self, key, default=None)
Definition: semantics.py:413
GaudiConfig2.semantics.PropertySemantics.name
name
Definition: semantics.py:38
GaudiConfig2.semantics.MappingSemantics
Definition: semantics.py:437
GaudiConfig2.semantics._ListHelper.__getitem__
def __getitem__(self, key)
Definition: semantics.py:279
GaudiConfig2.semantics._DictHelper.value_semantics
value_semantics
Definition: semantics.py:367
GaudiConfig2.semantics.OrderedSetSemantics
Definition: semantics.py:344
GaudiConfig2.semantics.StringSemantics.store
def store(self, value)
Definition: semantics.py:99
GaudiConfig2.semantics._DictHelper.keys
def keys(self)
Definition: semantics.py:399
GaudiConfig2.semantics._ListHelper.__len__
def __len__(self)
Definition: semantics.py:276
GaudiConfig2.semantics.extract_template_args
def extract_template_args(cpp_type)
Definition: semantics.py:237
GaudiConfig2.semantics._ListHelper.__delitem__
def __delitem__(self, key)
Definition: semantics.py:286
GaudiConfig2.semantics.getSemanticsFor
def getSemanticsFor(cpp_type, name=None)
Definition: semantics.py:474
GaudiConfig2.semantics._DictHelper.__len__
def __len__(self)
Definition: semantics.py:376
GaudiConfig2.semantics.PropertySemantics.__handled_types__
tuple __handled_types__
Definition: semantics.py:35
GaudiConfig2.semantics.BoolSemantics.store
def store(self, value)
Definition: semantics.py:108
GaudiConfig2.semantics.BoolSemantics
Definition: semantics.py:105
GaudiConfig2.semantics.FloatSemantics.store
def store(self, value)
Definition: semantics.py:115
GaudiConfig2.semantics._DictHelper.default
default
Definition: semantics.py:368
GaudiConfig2.semantics._ListHelper.data
data
Definition: semantics.py:292
GaudiConfig2.semantics.MappingSemantics.opt_value
def opt_value(self, value)
Definition: semantics.py:456
GaudiConfig2.semantics._DictHelper.opt_value
def opt_value(self)
Definition: semantics.py:427
GaudiConfig2.semantics._ListHelper
Definition: semantics.py:265
GaudiConfig2.semantics.MappingSemantics.__init__
def __init__(self, cpp_type, name=None)
Definition: semantics.py:440
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
GaudiConfig2.semantics.SequenceSemantics.value_semantics
value_semantics
Definition: semantics.py:321
GaudiConfig2.semantics._ListHelper._data
_data
Definition: semantics.py:269
GaudiConfig2.semantics.IntSemantics.INT_RANGES
dictionary INT_RANGES
Definition: semantics.py:127
GaudiConfig2.semantics._DictHelper.values
def values(self)
Definition: semantics.py:406
GaudiConfig2.semantics._DictHelper.__repr__
def __repr__(self)
Definition: semantics.py:433
GaudiConfig2.semantics._DictHelper
Definition: semantics.py:364
GaudiConfig2.semantics.SequenceSemantics.store
def store(self, value)
Definition: semantics.py:325
GaudiConfig2.semantics._DictHelper.__iter__
def __iter__(self)
Definition: semantics.py:395
GaudiConfig2.semantics._ListHelper.insert
def insert(self, key, value)
Definition: semantics.py:297
GaudiConfig2.semantics._ListHelper.value_semantics
value_semantics
Definition: semantics.py:267
GaudiConfig2.semantics._ListHelper.append
def append(self, value)
Definition: semantics.py:301
GaudiConfig2.semantics._DictHelper.update
def update(self, otherMap)
Definition: semantics.py:422
GaudiConfig2.semantics._DictHelper.is_dirty
is_dirty
Definition: semantics.py:370
GaudiConfig2.semantics.FloatSemantics
Definition: semantics.py:112
GaudiConfig2.semantics.ComponentSemantics.__init__
def __init__(self, cpp_type, name=None)
Definition: semantics.py:183
GaudiConfig2.semantics.MappingSemantics.key_semantics
key_semantics
Definition: semantics.py:443
GaudiConfig2.semantics._ListHelper.default
default
Definition: semantics.py:268
GaudiConfig2.semantics.PropertySemantics.merge
def merge(self, a, b)
Definition: semantics.py:80
GaudiConfig2.semantics._DictHelper.items
def items(self)
Definition: semantics.py:402
GaudiConfig2.semantics._ListHelper.__setitem__
def __setitem__(self, key, value)
Definition: semantics.py:282
GaudiConfig2.semantics._DictHelper.__setitem__
def __setitem__(self, key, value)
Definition: semantics.py:384
GaudiConfig2.semantics.ComponentSemantics.default
def default(self, value)
Definition: semantics.py:233
GaudiConfig2.semantics._DictHelper.key_semantics
key_semantics
Definition: semantics.py:366
GaudiConfig2.semantics.OrderedSetSemantics.merge
def merge(self, bb, aa)
Definition: semantics.py:357
GaudiConfig2.semantics.DefaultSemantics
DefaultSemantics
Definition: semantics.py:93
GaudiConfig2.semantics._DictHelper.data
def data(self)
Definition: semantics.py:373
GaudiConfig2.semantics.StringSemantics
Definition: semantics.py:96
GaudiConfig2.semantics._DictHelper.__getitem__
def __getitem__(self, key)
Definition: semantics.py:379
GaudiConfig2.semantics._ListHelper.__ne__
def __ne__(self, other)
Definition: semantics.py:294
GaudiConfig2.semantics._ListHelper.__init__
def __init__(self, semantics)
Definition: semantics.py:266
GaudiConfig2.semantics.PropertySemantics.store
def store(self, value)
Definition: semantics.py:60
GaudiConfig2.semantics._ListHelper.is_dirty
is_dirty
Definition: semantics.py:270
GaudiConfig2.semantics.MappingSemantics.value_semantics
value_semantics
Definition: semantics.py:444
GaudiConfig2.semantics.PropertySemantics
Definition: semantics.py:30
GaudiConfig2.semantics.PropertySemantics.opt_value
def opt_value(self, value)
Definition: semantics.py:72
GaudiConfig2.semantics.SequenceSemantics.__init__
def __init__(self, cpp_type, name=None, valueSem=None)
Definition: semantics.py:319
GaudiConfig2.semantics._ListHelper.__eq__
def __eq__(self, other)
Definition: semantics.py:291
GaudiConfig2.semantics.SequenceSemantics.opt_value
def opt_value(self, value)
Definition: semantics.py:335
GaudiConfig2.semantics.ComponentSemantics
Definition: semantics.py:171
GaudiConfig2.semantics._DictHelper.__init__
def __init__(self, key_semantics, value_semantics)
Definition: semantics.py:365
GaudiConfig2.semantics._DictHelper._data
_data
Definition: semantics.py:369
GaudiConfig2.semantics._ListHelper.extend
def extend(self, iterable)
Definition: semantics.py:305
GaudiConfig2.semantics.PropertySemantics.__init__
def __init__(self, cpp_type, name=None)
Definition: semantics.py:37
GaudiConfig2.semantics.SequenceSemantics
Definition: semantics.py:316
GaudiConfig2.semantics.MappingSemantics.default
def default(self, value)
Definition: semantics.py:451
GaudiConfig2.semantics._ListHelper.opt_value
def opt_value(self)
Definition: semantics.py:309