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))
239 return self.__component_type__
246 Merge the properties of the other instance into the current one. 248 The two instances have to be of the same type, have the same name 249 (or both unnamed) and the settings must be mergable (according to 254 'cannot merge instance of {} into an instance of {}'.
format(
255 type(other).__name__,
256 type(self).__name__))
257 if hasattr(self,
'name') != hasattr(other,
'name'):
259 'cannot merge a named configurable with an unnamed one')
260 if hasattr(self,
'name')
and (self.
name != other.name):
262 'cannot merge configurables with different names ({} and {})'.
265 for name
in other._descriptors:
266 if not other.is_property_set(name):
270 self, name, self._descriptors[name].__merge__(
271 self,
type(self), getattr(other, name)))
272 except ValueError
as err:
274 'conflicting settings for property {} of {}: {}'.
format(
276 if hasattr(self,
'name')
else type(self).__name__,
284 Create a Configurable specialization. 286 properties = namespace.pop(
'properties', {})
289 for pname, pargs
in properties.items()})
291 return type(name, (Configurable, ), namespace)
296 Return a dictionary with all explicitly set options, or with also the 297 defaults if explicit_defaults is set to True. 300 for c
in Configurable.instances.values():
301 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)