15from collections.abc
import MutableMapping, MutableSequence, MutableSet
21from .
import Configurable, Configurables
23_log = logging.getLogger(__name__)
24is_64bits = sys.maxsize > 2**32
29 Basic property semantics implementation, with no validation/transformation.
31 Not to be used directly for any actual property, use only specializations.
34 __handled_types__ = ()
55 h.match(value)
if hasattr(h,
"match")
else h == value
58 raise TypeError(
"C++ type {!r} not supported".
format(value))
63 Transformation for data when reading the property.
69 Validation/transformation of the data to be stored.
75 Allow overriding the definition of "is set" if we need helper types.
81 Option string version of value.
83 if hasattr(value,
"__opt_value__"):
84 return value.__opt_value__()
91 Used when merging two Configurable instances, by default just ensure
92 the two values do not conflict, but it can be overridden in
93 derived semantics to, for example, append to the two lists.
96 raise ValueError(
"cannot merge values %r and %r" % (a, b))
102 Special semantics that makes a deep copy of the default value on first access
103 and considers a property set if its value is different from the default.
105 This semantics is meant to be used whenever there is no specific semantic
106 (with proper change detection) implemented for a type.
109 __handled_types__ = (re.compile(
r".*"),)
115 return copy.deepcopy(value)
120 return super(DefaultSemantics, self).
store(value)
126 except AttributeError:
134 __handled_types__ = (
"std::string",)
137 if not isinstance(value, str):
138 raise TypeError(
"cannot set property {} to {!r}".
format(self.
name, value))
143 __handled_types__ = (
"bool",)
150 __handled_types__ = (
"float",
"double")
153 from numbers
import Number
155 if not isinstance(value, Number):
157 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
165 "signed char": (-128, 127),
166 "short": (-32768, 32767),
167 "int": (-2147483648, 2147483647),
169 (-9223372036854775808, 9223372036854775807)
171 else (-2147483648, 2147483647)
173 "long long": (-9223372036854775808, 9223372036854775807),
174 "unsigned char": (0, 255),
175 "unsigned short": (0, 65535),
176 "unsigned int": (0, 4294967295),
177 "unsigned long": (0, 18446744073709551615
if is_64bits
else 4294967295),
178 "unsigned long long": (0, 18446744073709551615),
181 __handled_types__ = tuple(INT_RANGES)
184 from numbers
import Number
186 if not isinstance(value, Number):
188 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
192 _log.warning(
"converted %s to %d in assignment to %s", value, v, self.
name)
194 if v < min_value
or v > max_value:
196 "value {} outside limits for {!r} {}".
format(
203_IDENTIFIER_RE =
r"[a-zA-Z_][a-zA-Z0-9_]*"
204_NS_IDENT_RE =
r"{ident}(::{ident})*".
format(ident=_IDENTIFIER_RE)
205_COMMA_SEPARATION_RE =
r"{exp}(,{exp})*"
209 __handled_types__ = (
213 r"AlgTool(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
216 r"Service(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
221 super(ComponentSemantics, self).
__init__(cpp_type)
230 if isinstance(value, Configurable):
232 elif isinstance(value, str):
234 if value
in Configurable.instances:
235 value = Configurable.instances[value]
239 t, n = value.split(
"/")
242 value = Configurables.getByType(t).getInstance(n)
245 "cannot assign {!r} to {!r}, requested string or {!r}".
format(
249 if value.__component_type__ != self.
cpp_type:
251 "wrong type for {!r}: expected {!r}, got {!r}".
format(
257 if value.__interfaces__:
258 if not self.
interfaces.issubset(value.__interfaces__):
260 "wrong interfaces for {!r}: required {}".
format(
264 except AttributeError:
269 return self.
store(value)
274 Semantics for component (tool, service) handles. On access, it will create the
275 corresponding Configurable instance and store it in the property.
278 __handled_types__ = (
"PrivateToolHandle",
"PublicToolHandle",
"ServiceHandle")
287 isinstance(value, Configurable)
288 and value.getGaudiType() == self.
handle_type.componentType
293 elif isinstance(value, GaudiHandle):
295 Configurables.getByType(value.getType()).getInstance(value.getName())
301 elif value
is None or value ==
"":
305 elif isinstance(value, str):
306 tn = value.split(
"/", maxsplit=1)
307 name = tn[1]
if len(tn) == 2
else tn[0]
308 return Configurables.getByType(tn[0]).getInstance(name)
310 raise TypeError(f
"cannot assign {value!r} ({type(value)}) to {self.name}")
313 return self.
store(value)
320 """Semantics for GaudiHandleArrays."""
322 __handled_types__ = (
323 "PrivateToolHandleArray",
324 "PublicToolHandleArray",
325 "ServiceHandleArray",
345 a.__getitem__(comp.getName()).
merge(comp)
354 Semantics for data handles.
357 __handled_types__ = (re.compile(
r"DataObject(Read|Write)Handle<.*>$"),)
364 if cpp_type.startswith(
"DataObjectReadHandle"):
366 elif cpp_type.startswith(
"DataObjectWriteHandle"):
369 raise TypeError(f
"C++ type {cpp_type} not supported")
372 if isinstance(value, DataHandle):
374 elif isinstance(value, str):
378 f
"cannot assign {value!r} ({type(value)}) to {self.name}"
379 ", expected string or DataHandle"
386 Return an iterator over the list of template arguments in a C++ type
389 >>> t = 'map<string, vector<int, allocator<int> >, allocator<v<i>, a<i>> >'
390 >>> list(extract_template_args(t))
391 ['string', 'vector<int, allocator<int> >', 'allocator<v<i>, a<i>>']
392 >>> list(extract_template_args('int'))
397 for p, c
in enumerate(cpp_type):
399 if template_level == 1:
400 yield cpp_type[arg_start:p].strip()
404 if template_level == 1:
408 if template_level == 0:
409 yield cpp_type[arg_start:p].strip()
435 raise RuntimeError(
"cannot remove elements from the default value")
439 return self.
data == other
457 return repr(self.
data)
461 __handled_types__ = (re.compile(
r"(std::)?(vector|list)<.*>$"),)
464 super(SequenceSemantics, self).
__init__(cpp_type)
479 if not isinstance(value, (list, _ListHelper, tuple)):
481 "list or tuple expected, got {!r} in assignment to {}".
format(
486 new_value.extend(value)
491 new_value.default = value
496 Option string version of value.
498 if not isinstance(value, _ListHelper):
500 return value.opt_value()
511 union = MutableSet.__ior__
512 update = MutableSet.__ior__
513 intersection = MutableSet.__iand__
514 difference = MutableSet.__isub__
515 symmetric_difference = MutableSet.__ixor__
528 return self.
data == other
531 for value
in self.
data:
540 raise RuntimeError(
"cannot remove elements from the default value")
545 raise RuntimeError(
"cannot remove elements from the default value")
554 return "{" + repr(sorted(self.
data))[1:-1] +
"}"
560 """Merge semantics for (unordered) sets."""
562 __handled_types__ = (re.compile(
r"(std::)?unordered_set<.*>$"),)
565 super(SetSemantics, self).
__init__(cpp_type)
581 if not isinstance(value, (set, _SetHelper, list, _ListHelper)):
583 "set expected, got {!r} in assignment to {}".
format(value, self.
name)
592 new_value.default = value
597 Option string version of value.
599 if not isinstance(value, _SetHelper):
601 return value.opt_value()
610 Extend the sequence-semantics with a merge-method to behave like a
611 OrderedSet: Values are unique but the order is maintained.
612 Use 'OrderedSet<T>' as fifth parameter of the Gaudi::Property<T> constructor
613 to invoke this merging method. Also applies to std::set.
616 __handled_types__ = (
617 re.compile(
r"(std::)?set<.*>$"),
618 re.compile(
r"^OrderedSet<.*>$"),
622 super(OrderedSetSemantics, self).
__init__(cpp_type)
632 def __init__(self, key_semantics, value_semantics):
659 raise RuntimeError(
"cannot remove elements from the default value")
663 for key
in self.
data:
680 def get(self, key, default=None):
691 for key, value
in otherMap.items():
701 return repr(self.
data)
705 __handled_types__ = (re.compile(
r"(std::)?(unordered_)?map<.*>$"),)
708 super(MappingSemantics, self).
__init__(cpp_type)
726 new_value.update(value)
731 new_value.default = value
736 Option string version of value.
738 if not isinstance(value, _DictHelper):
740 return value.opt_value()
743 """Merge two maps. Throw ValueError if there are conflicting key/value pairs."""
749 for k, v
in b.items():
757 f
"conflicting values in map for key {k}: {v} and {va}"
764 for c
in globals().values()
765 if isinstance(c, type)
766 and issubclass(c, PropertySemantics)
767 and c
not in (PropertySemantics, DefaultSemantics)
772 """Return semantics for given type. If no type-specific semantics can be found
773 return DefaultSemantics. In strict mode, raise a TypeError instead.
776 for semantics
in SEMANTICS:
778 return semantics(cpp_type)
783 raise TypeError(f
"No semantics found for {cpp_type}")
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
__setitem__(self, key, value)
__init__(self, key_semantics, value_semantics)
get(self, key, default=None)
__init__(self, semantics)
__setitem__(self, key, value)
__contains__(self, value)
__init__(self, semantics)
__init__(self, cpp_type, valueSem=None)
__init__(self, cpp_type, valueSem=None)
getSemanticsFor(cpp_type, strict=False)
extract_template_args(cpp_type)