12 _GLOBAL_INSTANCES =
False
17 Enable or disable the global instances database.
19 By default global instances are enabled.
21 global _GLOBAL_INSTANCES
22 if enable == _GLOBAL_INSTANCES:
26 not Configurable.instances
27 ),
"Configurable instances DB not empty, cannot be disabled"
28 _GLOBAL_INSTANCES = enable
33 Descriptor class to implement validation of Configurable properties.
36 def __init__(self, cpp_type, default, doc="undocumented", semantics=None):
37 from .semantics
import getSemanticsFor
52 if self.
name not in instance._properties
and hasattr(self.
semantics,
"default"):
60 del instance._properties[self.
name]
67 value = instance._properties[self.
name]
79 Return "merge" (according to the semantic) of the value
80 in this property and the incoming value.
89 Metaclass for Configurables.
92 def __new__(cls, name, bases, namespace, **kwds):
96 if isinstance(namespace[key], Property)
99 doc = namespace.get(
"__doc__",
"").rstrip()
100 doc +=
"\n\nProperties\n----------\n"
103 "- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n".
format(
109 namespace[
"__doc__"] = doc
110 namespace[
"_descriptors"] = props
111 slots = set(namespace.get(
"__slots__", []))
112 slots.update([
"_properties",
"_name"])
113 namespace[
"__slots__"] = tuple(slots)
114 result = type.__new__(cls, name, bases, namespace)
120 String representation of the value, such that it can be consumed be the
121 Gaudi option parsers.
123 if hasattr(value,
"__opt_repr__"):
124 return value.__opt_repr__()
125 elif isinstance(value, str):
126 return '"{}"'.
format(value.replace(
'"',
'\\"'))
132 Base class for all configurable instances.
140 if "parent" in kwargs:
141 parent = kwargs.pop(
"parent")
142 if isinstance(parent, str):
145 raise TypeError(
"name is needed when a parent is specified")
146 name =
"{}.{}".
format(parent.name, name)
149 elif not _GLOBAL_INSTANCES:
151 for key, value
in kwargs.items():
152 setattr(self, key, value)
161 raise AttributeError(
162 "{!r} instance was not named yet".
format(
type(self).__name__)
168 if value == self.
_name:
170 if not isinstance(value, str)
or not value:
172 "expected string, got {} instead".
format(
type(value).__name__)
174 if _GLOBAL_INSTANCES:
176 raise ValueError(
"name {!r} already used".
format(value))
186 if _GLOBAL_INSTANCES:
191 raise TypeError(
"name attribute cannot be deleted")
196 args.append(repr(self.
name))
197 except AttributeError:
200 return "{}({})".
format(
type(self).__name__,
", ".join(args))
205 state[
"name"] = self.
name
206 except AttributeError:
212 self.
name = state.get(
"name")
223 for p
in self._descriptors.values():
224 if explicit_defaults
or p.__is_set__(self,
type(self)):
225 out[
".".join([name, p.name])] =
opt_repr(
226 p.__opt_value__(self,
type(self))
231 return self._descriptors[propname].__is_set__(self,
type(self))
235 return cls.__component_type__
252 return {k: v.default
for k, v
in cls._descriptors.
items()}
256 return cls._descriptors[name].default
259 """Clone instance with all its properties."""
264 Merge the properties of the other instance into the current one.
266 The two instances have to be of the same type, have the same name
267 (or both unnamed) and the settings must be mergable (according to
274 "cannot merge instance of {} into an instance of {}".
format(
275 type(other).__name__,
type(self).__name__
278 if hasattr(self,
"name") != hasattr(other,
"name"):
279 raise ValueError(
"cannot merge a named configurable with an unnamed one")
280 if hasattr(self,
"name")
and (self.
name != other.name):
282 "cannot merge configurables with different names ({} and {})".
format(
283 self.
name, other.name
287 for name
in other._properties:
290 and self.
_properties[name] == other._properties[name]
297 self._descriptors[name].__merge__(
298 self,
type(self), getattr(other, name)
301 except ValueError
as err:
303 "conflicting settings for property {} of {}: {}".
format(
305 self.
name if hasattr(self,
"name")
else type(self).__name__,
315 Create a Configurable specialization.
317 properties = namespace.pop(
"properties", {})
318 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
320 return type(name, (Configurable,), namespace)
325 Return a dictionary with all explicitly set options, or with also the
326 defaults if explicit_defaults is set to True.
329 for c
in Configurable.instances.values():
330 opts.update(c.__opt_properties__(explicit_defaults))