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, basestring
if sys.version_info[0] == 2
else 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:
186 not isinstance(value, basestring
if sys.version_info[0] == 2
else str)
190 "expected string, got {} instead".
format(
type(value).__name__)
192 if _GLOBAL_INSTANCES:
194 raise ValueError(
"name {!r} already used".
format(value))
204 if _GLOBAL_INSTANCES:
209 raise TypeError(
"name attribute cannot be deleted")
214 args.append(repr(self.
name))
215 except AttributeError:
218 return "{}({})".
format(
type(self).__name__,
", ".join(args))
223 state[
"name"] = self.
name
224 except AttributeError:
230 self.
name = state.get(
"name")
241 for p
in self._descriptors.values():
242 if explicit_defaults
or p.__is_set__(self,
type(self)):
243 out[
".".join([name, p.name])] =
opt_repr(
244 p.__opt_value__(self,
type(self))
249 return self._descriptors[propname].__is_set__(self,
type(self))
253 return cls.__component_type__
270 return {k: v.default
for k, v
in cls._descriptors.
items()}
274 return cls._descriptors[name].default
278 Merge the properties of the other instance into the current one.
280 The two instances have to be of the same type, have the same name
281 (or both unnamed) and the settings must be mergable (according to
288 "cannot merge instance of {} into an instance of {}".
format(
289 type(other).__name__,
type(self).__name__
292 if hasattr(self,
"name") != hasattr(other,
"name"):
293 raise ValueError(
"cannot merge a named configurable with an unnamed one")
294 if hasattr(self,
"name")
and (self.
name != other.name):
296 "cannot merge configurables with different names ({} and {})".
format(
297 self.
name, other.name
301 for name
in other._properties:
304 and self.
_properties[name] == other._properties[name]
311 self._descriptors[name].__merge__(
312 self,
type(self), getattr(other, name)
315 except ValueError
as err:
317 "conflicting settings for property {} of {}: {}".
format(
319 self.
name if hasattr(self,
"name")
else type(self).__name__,
329 Create a Configurable specialization.
331 properties = namespace.pop(
"properties", {})
332 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
334 return type(name, (Configurable,), namespace)
339 Return a dictionary with all explicitly set options, or with also the
340 defaults if explicit_defaults is set to True.
343 for c
in Configurable.instances.values():
344 opts.update(c.__opt_properties__(explicit_defaults))