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:
29 assert not Configurable.instances, \
30 'Configurable instances DB not empty, cannot be disabled' 31 _GLOBAL_INSTANCES = enable
36 Descriptor class to implement validation of Configurable properties. 39 def __init__(self, cpp_type, default, doc='undocumented', semantics=None):
40 from .semantics
import getSemanticsFor
54 if (self.
name not in instance._properties
65 del instance._properties[self.
name]
72 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):
99 for key
in namespace
if isinstance(namespace[key], Property)
102 doc = namespace.get(
'__doc__',
'').rstrip()
103 doc +=
'\n\nProperties\n----------\n' 105 '- {name}: {p.cpp_type} ({p.default!r})\n {p.__doc__}\n'.
106 format(name=n, p=props[n])
for n
in props
108 namespace[
'__doc__'] = doc
109 if sys.version_info < (3, 6):
111 namespace[n].__set_name__(
None, n)
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__()
130 if sys.version_info >= (3, ):
131 exec (
'class ConfigMetaHelper(metaclass=ConfigurableMeta):\n pass')
135 __metaclass__ = ConfigurableMeta
140 Base class for all configurable instances. 147 if 'parent' in kwargs:
148 parent = kwargs.pop(
'parent')
149 if isinstance(parent,
150 basestring
if sys.version_info[0] == 2
else str):
153 raise TypeError(
'name is needed when a parent is specified')
154 name =
'{}.{}'.
format(parent.name, name)
157 elif not _GLOBAL_INSTANCES:
159 for key, value
in kwargs.items():
160 setattr(self, key, value)
169 raise AttributeError(
'{!r} instance was not named yet'.
format(
170 type(self).__name__))
175 if value == self.
_name:
177 if not isinstance(value, basestring
178 if sys.version_info[0] == 2
else str)
or not value:
179 raise TypeError(
'expected string, got {} instead'.
format(
180 type(value).__name__))
181 if _GLOBAL_INSTANCES:
183 raise ValueError(
'name {!r} already used'.
format(value))
193 if _GLOBAL_INSTANCES:
198 raise TypeError(
'name attribute cannot be deleted')
203 args.append(repr(self.
name))
204 except AttributeError:
208 return '{}({})'.
format(
type(self).__name__,
', '.join(args))
213 state[
'name'] = self.
name 214 except AttributeError:
219 self.
__init__(state.get(
'name'), **state[
'properties'])
229 for p
in self._descriptors.values():
230 if explicit_defaults
or p.__is_set__(self,
type(self)):
231 out[
'.'.join([name, p.name])] =
opt_repr(
232 p.__opt_value__(self,
type(self)))
236 return self._descriptors[propname].__is_set__(self,
type(self))
240 Merge the properties of the other instance into the current one. 242 The two instances have to be of the same type, have the same name 243 (or both unnamed) and the settings must be mergable (according to 248 'cannot merge instance of {} into an instance of {}'.
format(
249 type(other).__name__,
250 type(self).__name__))
251 if hasattr(self,
'name') != hasattr(other,
'name'):
253 'cannot merge a named configurable with an unnamed one')
254 if hasattr(self,
'name')
and (self.
name != other.name):
256 'cannot merge configurables with different names ({} and {})'.
259 for name
in other._descriptors:
260 if not other.is_property_set(name):
264 self, name, self._descriptors[name].__merge__(
265 self,
type(self), getattr(other, name)))
266 except ValueError
as err:
268 'conflicting settings for property {} of {}: {}'.
format(
270 if hasattr(self,
'name')
else type(self).__name__,
278 Create a Configurable specialization. 280 properties = namespace.pop(
'properties', {})
283 for pname, pargs
in properties.items()})
285 return type(name, (Configurable, ), namespace)
290 Return a dictionary with all explicitly set options, or with also the 291 defaults if explicit_defaults is set to True. 294 for c
in Configurable.instances.values():
295 opts.update(c.__opt_properties__(explicit_defaults))
def __opt_properties__(self, explicit_defaults=False)
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
def __is_set__(self, instance, owner)
def getSemanticsFor(cpp_type, name=None)
int merge(const char *target, const char *source, bool fixup=false, bool dbg=true)
def __set__(self, instance, value)
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))
def __init__(self, name=None, **kwargs)
def __init__(self, cpp_type, default, doc='undocumented', semantics=None)
def all_options(explicit_defaults=False)
def __merge__(self, instance, owner, value)
def is_property_set(self, propname)
def __setstate__(self, state)
def __set_name__(self, owner, name)
def __delete__(self, instance)
def getInstance(cls, name)
def __opt_value__(self, instance, owner)
def useGlobalInstances(enable)
def __get__(self, instance, owner)
def makeConfigurableClass(name, **namespace)