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)
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 f
"- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n"
108 for name, p
in props.items()
111 namespace[
"__doc__"] = doc
112 namespace[
"_descriptors"] = props
113 slots = set(namespace.get(
"__slots__", []))
114 slots.update([
"_properties",
"_name"])
115 namespace[
"__slots__"] = tuple(slots)
116 result = type.__new__(cls, name, bases, namespace)
122 String representation of the value, such that it can be consumed be the
123 Gaudi option parsers.
125 if hasattr(value,
"__opt_repr__"):
126 return value.__opt_repr__()
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 = f
"{parent.name}.{name}"
149 elif not _GLOBAL_INSTANCES:
151 for key, value
in kwargs.items():
152 setattr(self, key, value)
156 return cls.
instances.get(name)
or cls(name)
161 raise AttributeError(
162 f
"{repr(type(self).__name__)} instance was not named yet"
168 if value == self.
_name:
170 if not isinstance(value, str)
or not value:
171 raise TypeError(f
"expected string, got {type(value).__name__} instead")
172 if _GLOBAL_INSTANCES:
174 raise ValueError(f
"name {repr(value)} already used")
184 if _GLOBAL_INSTANCES:
189 raise TypeError(
"name attribute cannot be deleted")
194 args.append(repr(self.
name))
195 except AttributeError:
197 args.extend(f
"{k}={repr(v)}" for k, v
in self.
_properties.items())
198 return "{}({})".
format(type(self).__name__,
", ".join(args))
203 state[
"name"] = self.
name
204 except AttributeError:
210 self.
name = state.get(
"name")
216 return f
"{self.__cpp_type__}/{self.name}"
221 for p
in self._descriptors.values():
222 if explicit_defaults
or p.__is_set__(self, type(self)):
223 out[
".".join([name, p.name])] =
opt_repr(
224 p.__opt_value__(self, type(self))
229 return self._descriptors[propname].__is_set__(self, type(self))
233 return cls.__component_type__
243 return f
"{self.__cpp_type__}/{self.name}"
246 return f
"{self.__cpp_type__}/{self.name}"
250 return {k: v.default
for k, v
in cls._descriptors.items()}
254 return cls._descriptors[name].default
257 """Clone instance with all its properties."""
262 Merge the properties of the other instance into the current one.
264 The two instances have to be of the same type, have the same name
265 (or both unnamed) and the settings must be mergable (according to
270 if type(self)
is not type(other):
272 f
"cannot merge instance of {type(other).__name__} into an instance of { type(self).__name__}"
274 if hasattr(self,
"name") != hasattr(other,
"name"):
275 raise ValueError(
"cannot merge a named configurable with an unnamed one")
276 if hasattr(self,
"name")
and (self.
name != other.name):
278 f
"cannot merge configurables with different names ({self.name} and {other.name})"
281 for name
in other._properties:
284 and self.
_properties[name] == other._properties[name]
288 self.
_properties[name] = self._descriptors[name].__merge__(
289 self, type(self), getattr(other, name)
291 except ValueError
as err:
293 "conflicting settings for property {} of {}: {}".
format(
295 self.
name if hasattr(self,
"name")
else type(self).__name__,
305 Create a Configurable specialization.
307 properties = namespace.pop(
"properties", {})
308 namespace.update({pname:
Property(*pargs)
for pname, pargs
in properties.items()})
310 return type(name, (Configurable,), namespace)
315 Return a dictionary with all explicitly set options, or with also the
316 defaults if explicit_defaults is set to True.
319 for c
in Configurable.instances.values():
320 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)