12 from __future__
import absolute_import
16 _GLOBAL_INSTANCES =
False
21 Enable or disable the global instances database.
23 By default global instances are enabled.
25 global _GLOBAL_INSTANCES
26 if enable == _GLOBAL_INSTANCES:
30 not Configurable.instances
31 ),
"Configurable instances DB not empty, cannot be disabled"
32 _GLOBAL_INSTANCES = enable
37 Descriptor class to implement validation of Configurable properties.
40 def __init__(self, cpp_type, default, doc="undocumented", semantics=None):
41 from .semantics
import getSemanticsFor
56 if self.
name not in instance._properties
and hasattr(self.
semantics,
"default"):
64 del instance._properties[self.
name]
71 value = instance._properties[self.
name]
83 Return "merge" (according to the semantic) of the value
84 in this property and the incoming value.
93 Metaclass for Configurables.
96 def __new__(cls, name, bases, namespace, **kwds):
100 if isinstance(namespace[key], Property)
103 doc = namespace.get(
"__doc__",
"").rstrip()
104 doc +=
"\n\nProperties\n----------\n"
107 "- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n".
format(
113 namespace[
"__doc__"] = doc
114 if sys.version_info < (3, 6):
116 namespace[n].__set_name__(
None, n)
117 namespace[
"_descriptors"] = props
118 slots = set(namespace.get(
"__slots__", []))
119 slots.update([
"_properties",
"_name"])
120 namespace[
"__slots__"] = tuple(slots)
121 result = type.__new__(cls, name, bases, namespace)
127 String representation of the value, such that it can be consumed be the
128 Gaudi option parsers.
130 if hasattr(value,
"__opt_repr__"):
131 return value.__opt_repr__()
132 elif isinstance(value, str):
133 return '"{}"'.
format(value.replace(
'"',
'\\"'))
137 if sys.version_info >= (3,):
138 exec(
"class ConfigMetaHelper(metaclass=ConfigurableMeta):\n pass")
142 __metaclass__ = ConfigurableMeta
147 Base class for all configurable instances.
155 if "parent" in kwargs:
156 parent = kwargs.pop(
"parent")
157 if isinstance(parent, str):
160 raise TypeError(
"name is needed when a parent is specified")
161 name =
"{}.{}".
format(parent.name, name)
164 elif not _GLOBAL_INSTANCES:
166 for key, value
in kwargs.items():
167 setattr(self, key, value)
176 raise AttributeError(
177 "{!r} instance was not named yet".
format(
type(self).__name__)
183 if value == self.
_name:
185 if not isinstance(value, str)
or not value:
187 "expected string, got {} instead".
format(
type(value).__name__)
189 if _GLOBAL_INSTANCES:
191 raise ValueError(
"name {!r} already used".
format(value))
201 if _GLOBAL_INSTANCES:
206 raise TypeError(
"name attribute cannot be deleted")
211 args.append(repr(self.
name))
212 except AttributeError:
215 return "{}({})".
format(
type(self).__name__,
", ".join(args))
220 state[
"name"] = self.
name
221 except AttributeError:
227 self.
name = state.get(
"name")
238 for p
in self._descriptors.values():
239 if explicit_defaults
or p.__is_set__(self,
type(self)):
240 out[
".".join([name, p.name])] =
opt_repr(
241 p.__opt_value__(self,
type(self))
246 return self._descriptors[propname].__is_set__(self,
type(self))
250 return cls.__component_type__
267 return {k: v.default
for k, v
in cls._descriptors.
items()}
271 return cls._descriptors[name].default
274 """Clone instance with all its properties."""
279 Merge the properties of the other instance into the current one.
281 The two instances have to be of the same type, have the same name
282 (or both unnamed) and the settings must be mergable (according to
289 "cannot merge instance of {} into an instance of {}".
format(
290 type(other).__name__,
type(self).__name__
293 if hasattr(self,
"name") != hasattr(other,
"name"):
294 raise ValueError(
"cannot merge a named configurable with an unnamed one")
295 if hasattr(self,
"name")
and (self.
name != other.name):
297 "cannot merge configurables with different names ({} and {})".
format(
298 self.
name, other.name
302 for name
in other._properties:
305 and self.
_properties[name] == other._properties[name]
312 self._descriptors[name].__merge__(
313 self,
type(self), getattr(other, name)
316 except ValueError
as err:
318 "conflicting settings for property {} of {}: {}".
format(
320 self.
name if hasattr(self,
"name")
else type(self).__name__,
330 Create a Configurable specialization.
332 properties = namespace.pop(
"properties", {})
333 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
335 return type(name, (Configurable,), namespace)
340 Return a dictionary with all explicitly set options, or with also the
341 defaults if explicit_defaults is set to True.
344 for c
in Configurable.instances.values():
345 opts.update(c.__opt_properties__(explicit_defaults))