16from collections.abc
import MutableMapping, MutableSequence, MutableSet
22from .
import Configurable, Configurables
24_log = logging.getLogger(__name__)
25is_64bits = sys.maxsize > 2**32
30 Basic property semantics implementation, with no validation/transformation.
32 Not to be used directly for any actual property, use only specializations.
35 __handled_types__ = ()
56 h.match(value)
if hasattr(h,
"match")
else h == value
59 raise TypeError(
"C++ type {!r} not supported".
format(value))
64 Transformation for data when reading the property.
70 Validation/transformation of the data to be stored.
76 Allow overriding the definition of "is set" if we need helper types.
82 Option string version of value.
84 if hasattr(value,
"__opt_value__"):
85 return value.__opt_value__()
92 Used when merging two Configurable instances, by default just ensure
93 the two values do not conflict, but it can be overridden in
94 derived semantics to, for example, append to the two lists.
97 raise ValueError(
"cannot merge values %r and %r" % (a, b))
103 Special semantics that makes a deep copy of the default value on first access
104 and considers a property set if its value is different from the default.
106 This semantics is meant to be used whenever there is no specific semantic
107 (with proper change detection) implemented for a type.
110 __handled_types__ = (re.compile(
r".*"),)
116 return copy.deepcopy(value)
121 return super(DefaultSemantics, self).
store(value)
127 except AttributeError:
141 return isinstance(other, _JSONValue)
and self.
data == other.data
150 __handled_types__ = (
152 re.compile(
r"nlohmann::(?:json_abi[^:]*::)?basic_json<.*>$"),
157 return json.loads(json.dumps(value, allow_nan=
False))
160 data = json.loads(value)
if isinstance(value, str)
else self.
_normalize(value)
170 return value.explicitly_set
or value.data != value.default
173 if not isinstance(value, _JSONValue):
177 value.data, allow_nan=
False, separators=(
",",
":"), sort_keys=
True
183 __handled_types__ = (
"std::string",)
186 if not isinstance(value, str):
187 raise TypeError(
"cannot set property {} to {!r}".
format(self.
name, value))
192 __handled_types__ = (
"bool",)
199 __handled_types__ = (
"float",
"double")
202 from numbers
import Number
204 if not isinstance(value, Number):
206 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
214 "signed char": (-128, 127),
215 "short": (-32768, 32767),
216 "int": (-2147483648, 2147483647),
218 (-9223372036854775808, 9223372036854775807)
220 else (-2147483648, 2147483647)
222 "long long": (-9223372036854775808, 9223372036854775807),
223 "unsigned char": (0, 255),
224 "unsigned short": (0, 65535),
225 "unsigned int": (0, 4294967295),
226 "unsigned long": (0, 18446744073709551615
if is_64bits
else 4294967295),
227 "unsigned long long": (0, 18446744073709551615),
230 __handled_types__ = tuple(INT_RANGES)
233 from numbers
import Number
235 if not isinstance(value, Number):
237 "number expected, got {!r} in assignment to {}".
format(value, self.
name)
241 _log.warning(
"converted %s to %d in assignment to %s", value, v, self.
name)
243 if v < min_value
or v > max_value:
245 "value {} outside limits for {!r} {}".
format(
252_IDENTIFIER_RE =
r"[a-zA-Z_][a-zA-Z0-9_]*"
253_NS_IDENT_RE =
r"{ident}(::{ident})*".
format(ident=_IDENTIFIER_RE)
254_COMMA_SEPARATION_RE =
r"{exp}(,{exp})*"
258 __handled_types__ = (
262 r"AlgTool(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
265 r"Service(:{})?$".
format(_COMMA_SEPARATION_RE.format(exp=_NS_IDENT_RE))
270 super(ComponentSemantics, self).
__init__(cpp_type)
279 if isinstance(value, Configurable):
281 elif isinstance(value, str):
283 if value
in Configurable.instances:
284 value = Configurable.instances[value]
288 t, n = value.split(
"/")
291 value = Configurables.getByType(t).getInstance(n)
294 "cannot assign {!r} to {!r}, requested string or {!r}".
format(
298 if value.__component_type__ != self.
cpp_type:
300 "wrong type for {!r}: expected {!r}, got {!r}".
format(
306 if value.__interfaces__:
307 if not self.
interfaces.issubset(value.__interfaces__):
309 "wrong interfaces for {!r}: required {}".
format(
313 except AttributeError:
318 return self.
store(value)
323 Semantics for component (tool, service) handles. On access, it will create the
324 corresponding Configurable instance and store it in the property.
327 __handled_types__ = (
"PrivateToolHandle",
"PublicToolHandle",
"ServiceHandle")
336 isinstance(value, Configurable)
337 and value.getGaudiType() == self.
handle_type.componentType
342 elif isinstance(value, GaudiHandle):
344 Configurables.getByType(value.getType()).getInstance(value.getName())
350 elif value
is None or value ==
"":
354 elif isinstance(value, str):
355 tn = value.split(
"/", maxsplit=1)
356 name = tn[1]
if len(tn) == 2
else tn[0]
357 return Configurables.getByType(tn[0]).getInstance(name)
359 raise TypeError(f
"cannot assign {value!r} ({type(value)}) to {self.name}")
362 return self.
store(value)
370 return "[" +
",".join(map(repr, self)) +
"]"
374 """Semantics for GaudiHandleArrays."""
376 __handled_types__ = (
377 "PrivateToolHandleArray",
378 "PublicToolHandleArray",
379 "ServiceHandleArray",
397 handle.toStringProperty()
for handle
in value
404 a.__getitem__(comp.getName()).
merge(comp)
413 Semantics for data handles.
416 __handled_types__ = (re.compile(
r"DataObject(Read|Write)Handle<.*>$"),)
423 if cpp_type.startswith(
"DataObjectReadHandle"):
425 elif cpp_type.startswith(
"DataObjectWriteHandle"):
428 raise TypeError(f
"C++ type {cpp_type} not supported")
431 if isinstance(value, DataHandle):
433 elif isinstance(value, str):
437 f
"cannot assign {value!r} ({type(value)}) to {self.name}"
438 ", expected string or DataHandle"
448 Return an iterator over the list of template arguments in a C++ type
451 >>> t = 'map<string, vector<int, allocator<int> >, allocator<v<i>, a<i>> >'
452 >>> list(extract_template_args(t))
453 ['string', 'vector<int, allocator<int> >', 'allocator<v<i>, a<i>>']
454 >>> list(extract_template_args('int'))
459 for p, c
in enumerate(cpp_type):
461 if template_level == 1:
462 yield cpp_type[arg_start:p].strip()
466 if template_level == 1:
470 if template_level == 0:
471 yield cpp_type[arg_start:p].strip()
497 raise RuntimeError(
"cannot remove elements from the default value")
501 return self.
data == other
519 return repr(self.
data)
523 __handled_types__ = (re.compile(
r"(std::)?(vector|list)<.*>$"),)
526 super(SequenceSemantics, self).
__init__(cpp_type)
541 if not isinstance(value, (list, _ListHelper, tuple)):
543 "list or tuple expected, got {!r} in assignment to {}".
format(
548 new_value.extend(value)
553 new_value.default = value
558 Option string version of value.
560 if not isinstance(value, _ListHelper):
562 return value.opt_value()
573 union = MutableSet.__ior__
574 update = MutableSet.__ior__
575 intersection = MutableSet.__iand__
576 difference = MutableSet.__isub__
577 symmetric_difference = MutableSet.__ixor__
590 return self.
data == other
593 for value
in self.
data:
602 raise RuntimeError(
"cannot remove elements from the default value")
607 raise RuntimeError(
"cannot remove elements from the default value")
616 return "{" + repr(sorted(self.
data))[1:-1] +
"}"
622 """Merge semantics for (unordered) sets."""
624 __handled_types__ = (re.compile(
r"(std::)?unordered_set<.*>$"),)
627 super(SetSemantics, self).
__init__(cpp_type)
643 if not isinstance(value, (set, _SetHelper, list, _ListHelper)):
645 "set expected, got {!r} in assignment to {}".
format(value, self.
name)
654 new_value.default = value
659 Option string version of value.
661 if not isinstance(value, _SetHelper):
663 return value.opt_value()
672 Extend the sequence-semantics with a merge-method to behave like a
673 OrderedSet: Values are unique but the order is maintained.
674 Use 'OrderedSet<T>' as fifth parameter of the Gaudi::Property<T> constructor
675 to invoke this merging method. Also applies to std::set.
678 __handled_types__ = (
679 re.compile(
r"(std::)?set<.*>$"),
680 re.compile(
r"^OrderedSet<.*>$"),
684 super(OrderedSetSemantics, self).
__init__(cpp_type)
694 def __init__(self, key_semantics, value_semantics):
721 raise RuntimeError(
"cannot remove elements from the default value")
725 for key
in self.
data:
742 def get(self, key, default=None):
753 for key, value
in otherMap.items():
763 return repr(self.
data)
767 __handled_types__ = (re.compile(
r"(std::)?(unordered_)?map<.*>$"),)
770 super(MappingSemantics, self).
__init__(cpp_type)
788 new_value.update(value)
793 new_value.default = value
798 Option string version of value.
800 if not isinstance(value, _DictHelper):
802 return value.opt_value()
805 """Merge two maps. Throw ValueError if there are conflicting key/value pairs."""
811 for k, v
in b.items():
819 f
"conflicting values in map for key {k}: {v} and {va}"
826 for c
in globals().values()
827 if isinstance(c, type)
828 and issubclass(c, PropertySemantics)
829 and c
not in (PropertySemantics, DefaultSemantics)
834 """Return semantics for given type. If no type-specific semantics can be found
835 return DefaultSemantics. In strict mode, raise a TypeError instead.
838 for semantics
in SEMANTICS:
840 return semantics(cpp_type)
845 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, data, explicitly_set)
__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)