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__()
135 if sys.version_info >= (3,):
136 exec(
"class ConfigMetaHelper(metaclass=ConfigurableMeta):\n pass")
140 __metaclass__ = ConfigurableMeta
145 Base class for all configurable instances.
153 if "parent" in kwargs:
154 parent = kwargs.pop(
"parent")
155 if isinstance(parent, basestring
if sys.version_info[0] == 2
else str):
158 raise TypeError(
"name is needed when a parent is specified")
159 name =
"{}.{}".
format(parent.name, name)
162 elif not _GLOBAL_INSTANCES:
164 for key, value
in kwargs.items():
165 setattr(self, key, value)
174 raise AttributeError(
175 "{!r} instance was not named yet".
format(
type(self).__name__)
181 if value == self.
_name:
184 not isinstance(value, basestring
if sys.version_info[0] == 2
else str)
188 "expected string, got {} instead".
format(
type(value).__name__)
190 if _GLOBAL_INSTANCES:
192 raise ValueError(
"name {!r} already used".
format(value))
202 if _GLOBAL_INSTANCES:
207 raise TypeError(
"name attribute cannot be deleted")
212 args.append(repr(self.
name))
213 except AttributeError:
216 return "{}({})".
format(
type(self).__name__,
", ".join(args))
221 state[
"name"] = self.
name
222 except AttributeError:
228 self.
name = state.get(
"name")
239 for p
in self._descriptors.values():
240 if explicit_defaults
or p.__is_set__(self,
type(self)):
241 out[
".".join([name, p.name])] =
opt_repr(
242 p.__opt_value__(self,
type(self))
247 return self._descriptors[propname].__is_set__(self,
type(self))
251 return cls.__component_type__
268 return {k: v.default
for k, v
in cls._descriptors.
items()}
272 return cls._descriptors[name].default
276 Merge the properties of the other instance into the current one.
278 The two instances have to be of the same type, have the same name
279 (or both unnamed) and the settings must be mergable (according to
284 "cannot merge instance of {} into an instance of {}".
format(
285 type(other).__name__,
type(self).__name__
288 if hasattr(self,
"name") != hasattr(other,
"name"):
289 raise ValueError(
"cannot merge a named configurable with an unnamed one")
290 if hasattr(self,
"name")
and (self.
name != other.name):
292 "cannot merge configurables with different names ({} and {})".
format(
293 self.
name, other.name
297 for name
in other._descriptors:
298 if not other.is_property_set(name):
304 self._descriptors[name].__merge__(
305 self,
type(self), getattr(other, name)
308 except ValueError
as err:
310 "conflicting settings for property {} of {}: {}".
format(
312 self.
name if hasattr(self,
"name")
else type(self).__name__,
322 Create a Configurable specialization.
324 properties = namespace.pop(
"properties", {})
325 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
327 return type(name, (Configurable,), namespace)
332 Return a dictionary with all explicitly set options, or with also the
333 defaults if explicit_defaults is set to True.
336 for c
in Configurable.instances.values():
337 opts.update(c.__opt_properties__(explicit_defaults))