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
42 self.
semantics = getSemanticsFor(semantics, strict=
True)
57 if name
not in instance._properties
and hasattr(self.
semantics,
"default"):
65 del instance._properties[self.
name]
72 value = instance._properties[self.
name]
84 Return "merge" (according to the semantic) of the value
85 in this property and the incoming value.
94 Metaclass for Configurables.
97 def __new__(cls, name, bases, namespace, **kwds):
101 if isinstance(namespace[key], Property)
104 doc = namespace.get(
"__doc__",
"").rstrip()
105 doc +=
"\n\nProperties\n----------\n"
108 f
"- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n"
109 for name, p
in props.items()
112 namespace[
"__doc__"] = doc
113 namespace[
"_descriptors"] = props
114 slots = set(namespace.get(
"__slots__", []))
115 slots.update([
"_properties",
"_name"])
116 namespace[
"__slots__"] = tuple(slots)
117 result = type.__new__(cls, name, bases, namespace)
123 String representation of the value, such that it can be consumed be the
124 Gaudi option parsers.
126 if hasattr(value,
"__opt_repr__"):
127 return value.__opt_repr__()
133 Base class for all configurable instances.
141 if "parent" in kwargs:
142 parent = kwargs.pop(
"parent")
143 if isinstance(parent, str):
146 raise TypeError(
"name is needed when a parent is specified")
147 name = f
"{parent.name}.{name}"
150 elif not _GLOBAL_INSTANCES:
152 for key, value
in kwargs.items():
153 setattr(self, key, value)
157 return cls.
instances.get(name)
or cls(name)
162 raise AttributeError(
163 f
"{repr(type(self).__name__)} instance was not named yet"
169 if value == self.
_name:
171 if not isinstance(value, str)
or not value:
172 raise TypeError(f
"expected string, got {type(value).__name__} instead")
173 if _GLOBAL_INSTANCES:
175 raise ValueError(f
"name {repr(value)} already used")
185 if _GLOBAL_INSTANCES:
190 raise TypeError(
"name attribute cannot be deleted")
195 args.append(repr(self.
name))
196 except AttributeError:
198 args.extend(f
"{k}={repr(v)}" for k, v
in self.
_properties.items())
199 return "{}({})".
format(type(self).__name__,
", ".join(args))
204 state[
"name"] = self.
name
205 except AttributeError:
211 self.
name = state.get(
"name")
217 return f
"{self.__cpp_type__}/{self.name}"
222 for p
in self._descriptors.values():
223 if explicit_defaults
or p.__is_set__(self, type(self)):
224 out[
".".join([name, p.name])] =
opt_repr(
225 p.__opt_value__(self, type(self))
230 return self._descriptors[propname].__is_set__(self, type(self))
234 return cls.__component_type__
244 return f
"{self.__cpp_type__}/{self.name}"
247 return f
"{self.__cpp_type__}/{self.name}"
251 return {k: v.default
for k, v
in cls._descriptors.items()}
255 return cls._descriptors[name].default
258 """Clone instance with all its properties."""
263 Merge the properties of the other instance into the current one.
265 The two instances have to be of the same type, have the same name
266 (or both unnamed) and the settings must be mergable (according to
271 if type(self)
is not type(other):
273 f
"cannot merge instance of {type(other).__name__} into an instance of { type(self).__name__}"
275 if hasattr(self,
"name") != hasattr(other,
"name"):
276 raise ValueError(
"cannot merge a named configurable with an unnamed one")
277 if hasattr(self,
"name")
and (self.
name != other.name):
279 f
"cannot merge configurables with different names ({self.name} and {other.name})"
282 for name
in other._properties:
285 and self.
_properties[name] == other._properties[name]
289 self.
_properties[name] = self._descriptors[name].__merge__(
290 self, type(self), getattr(other, name)
292 except ValueError
as err:
294 "conflicting settings for property {} of {}: {}".
format(
296 self.
name if hasattr(self,
"name")
else type(self).__name__,
306 Create a Configurable specialization.
308 properties = namespace.pop(
"properties", {})
309 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
311 return type(name, (Configurable,), namespace)
316 Return a dictionary with all explicitly set options, or with also the
317 defaults if explicit_defaults is set to True.
320 for c
in Configurable.instances.values():
321 opts.update(c.__opt_properties__(explicit_defaults))
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
__init__(self, name=None, **kwargs)
__setstate__(self, state)
getDefaultProperty(cls, name)
clone(self, newname=None)
getDefaultProperties(cls)
__opt_properties__(self, explicit_defaults=False)
is_property_set(self, propname)
__get__(self, instance, owner)
__init__(self, cpp_type, default, doc="undocumented", semantics=None)
__delete__(self, instance)
__opt_value__(self, instance, owner)
__set__(self, instance, value)
__set_name__(self, owner, name)
__is_set__(self, instance, owner)
__merge__(self, instance, owner, value)
int merge(const char *target, const char *source, bool fixup=false, bool dbg=true)
all_options(explicit_defaults=False)
useGlobalInstances(enable)
makeConfigurableClass(name, **namespace)