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