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:
220 self.
name = state.get(
'name')
231 for p
in self._descriptors.values():
232 if explicit_defaults
or p.__is_set__(self,
type(self)):
233 out[
'.'.join([name, p.name])] =
opt_repr(
234 p.__opt_value__(self,
type(self)))
238 return self._descriptors[propname].__is_set__(self,
type(self))
242 return cls.__component_type__
259 return {k: v.default
for k, v
in cls._descriptors.
items()}
263 return cls._descriptors[name].default
267 Merge the properties of the other instance into the current one.
269 The two instances have to be of the same type, have the same name
270 (or both unnamed) and the settings must be mergable (according to
275 'cannot merge instance of {} into an instance of {}'.
format(
276 type(other).__name__,
277 type(self).__name__))
278 if hasattr(self,
'name') != hasattr(other,
'name'):
280 'cannot merge a named configurable with an unnamed one')
281 if hasattr(self,
'name')
and (self.
name != other.name):
283 'cannot merge configurables with different names ({} and {})'.
286 for name
in other._descriptors:
287 if not other.is_property_set(name):
291 self, name, self._descriptors[name].__merge__(
292 self,
type(self), getattr(other, name)))
293 except ValueError
as err:
295 'conflicting settings for property {} of {}: {}'.
format(
297 if hasattr(self,
'name')
else type(self).__name__,
305 Create a Configurable specialization.
307 properties = namespace.pop(
'properties', {})
310 for pname, pargs
in properties.items()})
312 return type(name, (Configurable, ), namespace)
317 Return a dictionary with all explicitly set options, or with also the
318 defaults if explicit_defaults is set to True.
321 for c
in Configurable.instances.values():
322 opts.update(c.__opt_properties__(explicit_defaults))