15 from collections.abc
import MutableMapping, MutableSequence, MutableSet
20 from .
import Configurable, Configurables
22 _log = logging.getLogger(__name__)
23 is_64bits = sys.maxsize > 2**32
28 Basic property semantics implementation, with no validation/transformation.
30 Not to be used directly for any actual property, use only specializations.
33 __handled_types__ = ()
54 h.match(value)
if hasattr(h,
"match")
else h == value
57 raise TypeError(
"C++ type {!r} not supported".
format(value))
62 Transformation for data when reading the property.
68 Validation/transformation of the data to be stored.
74 Allow overriding the definition of "is set" if we need helper types.
80 Option string version of value.
82 if hasattr(value,
"__opt_value__"):
83 return value.__opt_value__()
90 Used when merging two Configurable instances, by default just ensure
91 the two values do not conflict, but it can be overridden in
92 derived semantics to, for example, append to the two lists.
95 raise ValueError(
"cannot merge values %r and %r" % (a, b))
101 Special semantics that makes a deep copy of the default value on first access
102 and considers a property set if its value is different from the default.
104 This semantics is meant to be used whenever there is no specific semantic
105 (with proper change detection) implemented for a type.
108 __handled_types__ = (re.compile(
r".*"),)
114 return copy.deepcopy(value)
119 return super(DefaultSemantics, self).
store(value)
125 except AttributeError:
133 __handled_types__ = (
"std::string",)
136 if not isinstance(value, str):
137 raise TypeError(
"cannot set property {} to {!r}".
format(self.
name, value))
142 __handled_types__ = (
"bool",)
149 __handled_types__ = (
"float",
"double")
152 from numbers
import Number
154 if not isinstance(value, Number):
156 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
164 "signed char": (-128, 127),
165 "short": (-32768, 32767),
166 "int": (-2147483648, 2147483647),
168 (-9223372036854775808, 9223372036854775807)
170 else (-2147483648, 2147483647)
172 "long long": (-9223372036854775808, 9223372036854775807),
173 "unsigned char": (0, 255),
174 "unsigned short": (0, 65535),
175 "unsigned int": (0, 4294967295),
176 "unsigned long": (0, 18446744073709551615
if is_64bits
else 4294967295),
177 "unsigned long long": (0, 18446744073709551615),
180 __handled_types__ = tuple(INT_RANGES)
183 from numbers
import Number
185 if not isinstance(value, Number):
187 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
191 _log.warning(
"converted %s to %d in assignment to %s", value, v, self.
name)
193 if v < min_value
or v > max_value:
195 "value {} outside limits for {!r} {}".
format(
202 _IDENTIFIER_RE =
r"[a-zA-Z_][a-zA-Z0-9_]*"
203 _NS_IDENT_RE =
r"{ident}(::{ident})*".
format(ident=_IDENTIFIER_RE)
204 _COMMA_SEPARATION_RE =
r"{exp}(,{exp})*"
208 __handled_types__ = (
212 r"AlgTool(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
215 r"Service(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
220 super(ComponentSemantics, self).
__init__(cpp_type)
229 if isinstance(value, Configurable):
231 elif isinstance(value, str):
233 if value
in Configurable.instances:
234 value = Configurable.instances[value]
238 t, n = value.split(
"/")
241 value = Configurables.getByType(t).getInstance(n)
244 "cannot assign {!r} to {!r}, requested string or {!r}".
format(
248 if value.__component_type__ != self.
cpp_type:
250 "wrong type for {!r}: expected {!r}, got {!r}".
format(
256 if value.__interfaces__:
257 if not self.
interfaces.issubset(value.__interfaces__):
259 "wrong interfaces for {!r}: required {}".
format(
263 except AttributeError:
268 return self.
store(value)
273 Semantics for component (tool, service) handles. On access, it will create the
274 corresponding Configurable instance and store it in the property.
277 __handled_types__ = (
"PrivateToolHandle",
"PublicToolHandle",
"ServiceHandle")
286 isinstance(value, Configurable)
287 and value.getGaudiType() == self.
handle_type.componentType
292 elif isinstance(value, GaudiHandle):
294 Configurables.getByType(value.getType()).getInstance(value.getName())
300 elif value
is None or value ==
"":
304 elif isinstance(value, str):
305 tn = value.split(
"/", maxsplit=1)
306 name = tn[1]
if len(tn) == 2
else tn[0]
307 return Configurables.getByType(tn[0]).getInstance(name)
309 raise TypeError(f
"cannot assign {value!r} ({type(value)}) to {self.name}")
312 return self.
store(value)
319 """Semantics for GaudiHandleArrays."""
321 __handled_types__ = (
322 "PrivateToolHandleArray",
323 "PublicToolHandleArray",
324 "ServiceHandleArray",
344 a.__getitem__(comp.getName()).
merge(comp)
353 Return an iterator over the list of template arguments in a C++ type
356 >>> t = 'map<string, vector<int, allocator<int> >, allocator<v<i>, a<i>> >'
357 >>> list(extract_template_args(t))
358 ['string', 'vector<int, allocator<int> >', 'allocator<v<i>, a<i>>']
359 >>> list(extract_template_args('int'))
364 for p, c
in enumerate(cpp_type):
366 if template_level == 1:
367 yield cpp_type[arg_start:p].strip()
371 if template_level == 1:
375 if template_level == 0:
376 yield cpp_type[arg_start:p].strip()
391 return len(self.
data)
402 raise RuntimeError(
"cannot remove elements from the default value")
424 return repr(self.
data)
428 __handled_types__ = (re.compile(
r"(std::)?(vector|list)<.*>$"),)
431 super(SequenceSemantics, self).
__init__(cpp_type)
446 if not isinstance(value, (list, _ListHelper, tuple)):
448 "list or tuple expected, got {!r} in assignment to {}".
format(
453 new_value.extend(value)
458 new_value.default = value
463 Option string version of value.
465 if not isinstance(value, _ListHelper):
467 return value.opt_value()
478 union = MutableSet.__ior__
479 update = MutableSet.__ior__
480 intersection = MutableSet.__iand__
481 difference = MutableSet.__isub__
482 symmetric_difference = MutableSet.__ixor__
489 return len(self.
data)
498 for value
in self.
data:
507 raise RuntimeError(
"cannot remove elements from the default value")
512 raise RuntimeError(
"cannot remove elements from the default value")
521 return "{" + repr(sorted(self.
data))[1:-1] +
"}"
527 """Merge semantics for (unordered) sets."""
529 __handled_types__ = (re.compile(
r"(std::)?unordered_set<.*>$"),)
532 super(SetSemantics, self).
__init__(cpp_type)
548 if not isinstance(value, (set, _SetHelper, list, _ListHelper)):
550 "set expected, got {!r} in assignment to {}".
format(value, self.
name)
559 new_value.default = value
564 Option string version of value.
566 if not isinstance(value, _SetHelper):
568 return value.opt_value()
577 Extend the sequence-semantics with a merge-method to behave like a
578 OrderedSet: Values are unique but the order is maintained.
579 Use 'OrderedSet<T>' as fifth parameter of the Gaudi::Property<T> constructor
580 to invoke this merging method. Also applies to std::set.
583 __handled_types__ = (
584 re.compile(
r"(std::)?set<.*>$"),
585 re.compile(
r"^OrderedSet<.*>$"),
589 super(OrderedSetSemantics, self).
__init__(cpp_type)
599 def __init__(self, key_semantics, value_semantics):
611 return len(self.
data)
626 raise RuntimeError(
"cannot remove elements from the default value")
630 for key
in self.
data:
647 def get(self, key, default=None):
658 for key, value
in otherMap.items():
668 return repr(self.
data)
672 __handled_types__ = (re.compile(
r"(std::)?(unordered_)?map<.*>$"),)
675 super(MappingSemantics, self).
__init__(cpp_type)
693 new_value.update(value)
698 new_value.default = value
703 Option string version of value.
705 if not isinstance(value, _DictHelper):
707 return value.opt_value()
712 for c
in globals().values()
713 if isinstance(c, type)
714 and issubclass(c, PropertySemantics)
715 and c
not in (PropertySemantics, DefaultSemantics)
720 for semantics
in SEMANTICS:
722 return semantics(cpp_type)