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"
389 Return an iterator over the list of template arguments in a C++ type
392 >>> t = 'map<string, vector<int, allocator<int> >, allocator<v<i>, a<i>> >'
393 >>> list(extract_template_args(t))
394 ['string', 'vector<int, allocator<int> >', 'allocator<v<i>, a<i>>']
395 >>> list(extract_template_args('int'))
400 for p, c
in enumerate(cpp_type):
402 if template_level == 1:
403 yield cpp_type[arg_start:p].strip()
407 if template_level == 1:
411 if template_level == 0:
412 yield cpp_type[arg_start:p].strip()
438 raise RuntimeError(
"cannot remove elements from the default value")
442 return self.
data == other
460 return repr(self.
data)
464 __handled_types__ = (re.compile(
r"(std::)?(vector|list)<.*>$"),)
467 super(SequenceSemantics, self).
__init__(cpp_type)
482 if not isinstance(value, (list, _ListHelper, tuple)):
484 "list or tuple expected, got {!r} in assignment to {}".
format(
489 new_value.extend(value)
494 new_value.default = value
499 Option string version of value.
501 if not isinstance(value, _ListHelper):
503 return value.opt_value()
514 union = MutableSet.__ior__
515 update = MutableSet.__ior__
516 intersection = MutableSet.__iand__
517 difference = MutableSet.__isub__
518 symmetric_difference = MutableSet.__ixor__
531 return self.
data == other
534 for value
in self.
data:
543 raise RuntimeError(
"cannot remove elements from the default value")
548 raise RuntimeError(
"cannot remove elements from the default value")
557 return "{" + repr(sorted(self.
data))[1:-1] +
"}"
563 """Merge semantics for (unordered) sets."""
565 __handled_types__ = (re.compile(
r"(std::)?unordered_set<.*>$"),)
568 super(SetSemantics, self).
__init__(cpp_type)
584 if not isinstance(value, (set, _SetHelper, list, _ListHelper)):
586 "set expected, got {!r} in assignment to {}".
format(value, self.
name)
595 new_value.default = value
600 Option string version of value.
602 if not isinstance(value, _SetHelper):
604 return value.opt_value()
613 Extend the sequence-semantics with a merge-method to behave like a
614 OrderedSet: Values are unique but the order is maintained.
615 Use 'OrderedSet<T>' as fifth parameter of the Gaudi::Property<T> constructor
616 to invoke this merging method. Also applies to std::set.
619 __handled_types__ = (
620 re.compile(
r"(std::)?set<.*>$"),
621 re.compile(
r"^OrderedSet<.*>$"),
625 super(OrderedSetSemantics, self).
__init__(cpp_type)
635 def __init__(self, key_semantics, value_semantics):
662 raise RuntimeError(
"cannot remove elements from the default value")
666 for key
in self.
data:
683 def get(self, key, default=None):
694 for key, value
in otherMap.items():
704 return repr(self.
data)
708 __handled_types__ = (re.compile(
r"(std::)?(unordered_)?map<.*>$"),)
711 super(MappingSemantics, self).
__init__(cpp_type)
729 new_value.update(value)
734 new_value.default = value
739 Option string version of value.
741 if not isinstance(value, _DictHelper):
743 return value.opt_value()
746 """Merge two maps. Throw ValueError if there are conflicting key/value pairs."""
752 for k, v
in b.items():
760 f
"conflicting values in map for key {k}: {v} and {va}"
767 for c
in globals().values()
768 if isinstance(c, type)
769 and issubclass(c, PropertySemantics)
770 and c
not in (PropertySemantics, DefaultSemantics)
775 """Return semantics for given type. If no type-specific semantics can be found
776 return DefaultSemantics. In strict mode, raise a TypeError instead.
779 for semantics
in SEMANTICS:
781 return semantics(cpp_type)
786 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)