19 from inspect
import isclass
55 "ConfigurableAlgorithm",
56 "ConfigurableAlgTool",
57 "ConfigurableAuditor",
58 "ConfigurableService",
66 "appendPostConfigAction",
67 "removePostConfigAction",
73 log = logging.getLogger(
"Configurable")
78 Expand environment variables "data".
79 Data can be string, list, tuple and dictionary. For collection, all the
80 contained strings will be manipulated (recursively).
86 return os.path.expandvars(data)
87 elif typ
in [list, tuple]:
102 Error occurred in the configuration process.
111 class PropertyReference(object):
116 return "@%s" % self.
name
121 refname, refprop = self.
name.rsplit(
".", 1)
122 if refname
in Configurable.allConfigurables:
123 conf = Configurable.allConfigurables[refname]
124 retval = getattr(conf, refprop)
125 if hasattr(retval,
"getFullName"):
126 retval = retval.getFullName()
128 raise NameError(
"name '%s' not found resolving '%s'" % (refname, self))
132 """This function allow transparent integration with
133 Configurable.getValuedProperties.
140 except AttributeError:
149 """Base class for Gaudi components that implement the IProperty interface.
150 Provides most of the boilerplate code, but the actual useful classes
151 are its derived ConfigurableAlgorithm, ConfigurableService, and
152 ConfigurableAlgTool."""
158 propertyNoValue =
"<no value>"
160 printHeaderWidth = 100
173 allConfigurables = {}
174 configurableServices = {}
177 _configurationLocked =
False
180 """To Gaudi, any object with the same type/name is the same object. Hence,
181 this is mimicked in the configuration: instantiating a new Configurable
182 of a type with the same name will return the same instance."""
186 func_defaults = cls.
__init__.__defaults__
190 name = kwargs[
"name"]
191 elif "name" in func_code.co_varnames:
193 index = list(func_code.co_varnames).
index(
"name")
196 name = args[index - 1]
199 name = func_defaults[index - (len(args) + 1)]
204 except (IndexError, TypeError):
206 'no "name" argument while instantiating "%s"' % cls.__name__
211 if hasattr(cls,
"DefaultedName"):
212 name = cls.DefaultedName
215 elif not name
or not isinstance(name, str):
218 "could not retrieve name from %s.__init__ arguments" % cls.__name__
223 if issubclass(cls, ConfigurableAlgTool)
and "." not in name:
224 name =
"ToolSvc." + name
234 if name
in cls.configurables:
235 conf = cls.configurables[name]
237 cls.configurables[conf.getType()] = conf
239 for n, v
in kwargs.items():
244 and "_enabled" not in kwargs
245 and isinstance(conf, ConfigurableUser)
249 setattr(conf,
"_enabled",
True)
253 spos = name.find(
"/")
256 ti_name =
"%s/%s" % (name, name)
257 if ti_name
in cls.configurables:
259 return cls.configurables[ti_name]
264 if i_name == name[spos + 1 :]
and i_name
in cls.configurables:
266 return cls.configurables[i_name]
274 and i_name == name[spos + 1 :]
279 if conf.__class__
is ConfigurableGeneric:
283 newconf = object.__new__(cls)
284 cls.
__init__(newconf, *args, **kwargs)
289 for n
in newconf.__slots__:
291 for n
in conf._properties:
292 if names[n.lower()] != n:
294 "Option '%s' was used for %s, but the correct spelling is '%s'"
295 % (n, name, names[n.lower()])
297 setattr(newconf, names[n.lower()], getattr(conf, n))
298 for n, v
in kwargs.items():
299 setattr(newconf, n, v)
300 cls.configurables[name] = newconf
306 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
308 conf.__class__.__name__,
316 for n, v
in kwargs.items():
321 conf = object.__new__(cls)
325 cls.configurables[name] = conf
327 for base
in cls.__bases__:
328 if base.__name__ ==
"ConfigurableService":
340 klass = self.__class__
343 if klass == Configurable:
345 "%s is an ABC and can not be instantiated" % str(Configurable)
357 for meth, nArgs
in meths.items():
359 f = getattr(klass, meth)
360 except AttributeError:
361 raise NotImplementedError(
362 "%s is missing in class %s" % (meth, str(klass))
366 nargcount = f.__code__.co_argcount
367 fdefaults = f.__defaults__
368 ndefaults = fdefaults
and len(fdefaults)
or 0
369 if not nargcount - ndefaults <= nArgs <= nargcount:
371 "%s.%s requires exactly %d arguments" % (klass, meth, nArgs)
380 if hasattr(self.__class__,
"DefaultedName"):
381 self.
_name = self.__class__.DefaultedName
402 for name, proxy
in self._properties.items():
404 dict[name] = proxy.__get__(self)
405 except AttributeError:
408 dict[
"_Configurable__children"] = self.
__children
409 dict[
"_Configurable__tools"] = self.
__tools
410 dict[
"_name"] = self.
_name
418 from contextlib
import contextmanager
429 for n, v
in dict.items():
441 newconf = object.__new__(self.__class__)
444 for proxy
in self._properties.values():
446 proxy.__set__(newconf, proxy.__get__(self))
447 except AttributeError:
457 if not type(configs)
in (list, tuple):
464 if not isinstance(cfg, Configurable):
465 raise TypeError(
"'%s' is not a Configurable" % str(cfg))
470 ccjo = cc.getJobOptName()
472 if c.getJobOptName() == ccjo:
474 "attempt to add a duplicate ... dupe ignored%s",
483 descr.__set__(self, cc)
485 setattr(self, cc.getName(), cc)
486 except AttributeError:
495 if attr
in self._properties:
496 if isinstance(self._properties[attr].__get__(self), DataHandle):
497 return self._properties[attr].__get__(self)
500 if c.getName() == attr:
503 raise AttributeError(
504 "'%s' object has no attribute '%s'" % (self.__class__, attr)
510 "%s: Configuration cannot be modified after the ApplicationMgr has been started."
515 except AttributeError:
516 raise AttributeError(
517 "Configurable '%s' does not have property '%s'."
518 % (self.__class__.__name__, name)
525 prop = self._properties[attr]
526 prop.__delete__(self)
527 prop.__set__(self, prop.default)
537 if c.getName() == attr:
542 del self.__dict__[attr]
543 except (AttributeError, KeyError):
550 if not isinstance(items, (list, tuple)):
560 return copy.deepcopy(child)
574 if hasattr(cc,
"setParent")
and parent:
577 except RuntimeError
as e:
579 log.error(str(e) +
"%s", error_explanation)
580 ccbd = cc.configurables[cc.getJobOptName()]
583 for proxy
in self._properties.values():
584 if cc
in proxy.history:
585 proxy.__set__(ccbd, proxy.__get__(cc))
598 log.error(
"children() is deprecated, use getChildren() instead for consistency")
600 "getChildren() returns a copy; to add a child, use 'parent += child'%s",
606 """Get all (private) configurable children, both explicit ones (added with +=)
607 and the ones in the private GaudiHandle properties"""
610 for proxy
in self._properties.values():
612 c = proxy.__get__(self)
613 except AttributeError:
616 if isinstance(c, Configurable)
and not c.isPublic():
618 elif isinstance(c, GaudiHandle):
620 conf = c.configurable
621 except AttributeError:
624 if not conf.isPublic():
626 elif isinstance(c, GaudiHandleArray):
630 if isinstance(ci, Configurable):
634 conf = ci.configurable
635 except AttributeError:
647 elems.append(c.getFullName())
652 if not hasattr(self,
"_initok")
or not self.
_initok:
655 "Configurable.__init__ not called in %s override"
656 % self.__class__.__name__
671 handle = self.getHandle()
673 log.debug(
"no handle for %s: not transporting properties", self.
_name)
677 for name
in self._properties.
keys():
678 if hasattr(self, name):
679 setattr(handle, name, getattr(self, name))
686 for name, proxy
in self._properties.items():
688 props[name] = proxy.__get__(self)
689 except AttributeError:
690 props[name] = Configurable.propertyNoValue
695 """Get all properties with their description string as { name : (value, desc) }."""
697 for name, proxy
in self._properties.items():
699 props[name] = (proxy.__get__(self), proxy.__doc__)
700 except AttributeError:
701 props[name] = (Configurable.propertyNoValue, proxy.__doc__)
706 for name, proxy
in self._properties.items():
708 value = proxy.__get__(self)
709 if hasattr(value,
"getFullName"):
710 value = value.getFullName()
711 elif isinstance(value, (list, set, tuple)):
714 if hasattr(i,
"getFullName"):
715 new_value.append(i.getFullName())
718 value =
type(value)(new_value)
719 elif isinstance(value, dict):
722 if hasattr(value[i],
"getFullName"):
725 new_value[i] = value[i]
744 for k, v
in cls._properties.items():
745 if k
not in c.__dict__
and hasattr(v,
"default"):
746 c.__dict__[k] = v.default
759 if name
in c.__dict__:
760 return c.__dict__[name]
764 v = cls._properties[name]
765 if hasattr(v,
"default"):
773 """Returns the value of the given property."""
774 if hasattr(self, name):
775 return getattr(self, name)
780 """Set the value of a given property"""
781 return setattr(self, name, value)
784 """Tell if the property 'name' has been set or not.
786 Because of a problem with list and dictionary properties, in those cases
787 if the value is equal to the default, the property is considered as not
790 if not hasattr(self, name):
793 if isinstance(default, (list, dict, set, DataHandle, GaudiHandleArray)):
794 value = getattr(self, name)
795 return value != default
816 "jobOptName() is deprecated, use getJobOptName() instead for consistency%s",
831 if log.isEnabledFor(logging.DEBUG):
839 def clone(self, name=None, **kwargs):
841 if hasattr(self,
"DefaultedName"):
842 name = self.DefaultedName
844 name = self.getType()
846 newconf = Configurable.__new__(self.__class__, name)
847 self.__class__.
__init__(newconf, name)
849 for proxy
in self._properties.values():
851 value = proxy.__get__(self)
852 if isinstance(value, (str, list, dict, tuple, set)):
854 value =
type(value)(value)
855 proxy.__set__(newconf, value)
856 except AttributeError:
859 for c
in self.__children:
862 for n, t
in self.__tools.items():
863 newconf.addTool(t, n)
865 for name, value
in kwargs.items():
866 setattr(newconf, name, value)
872 dot = fullname.find(
".")
874 parentname = fullname[:dot]
875 longname = fullname[dot + 1 :]
879 dot = longname.find(
".")
881 name = longname[:dot]
884 return parentname, name, longname
887 if isclass(tool)
and issubclass(tool, ConfigurableAlgTool):
891 elif isinstance(tool, ConfigurableAlgTool):
893 name = tool.splitName()[1]
894 priv_tool = tool.clone(self.
getName() +
"." + name)
897 classname = tool.__name__
899 classname =
type(tool).__name__
901 "addTool requires AlgTool configurable. Got %s type" % classname
906 setattr(self, name, self.
__tools[name])
922 handle = __main__.Service(svc)
927 if hasattr(self,
"configure" + svc):
928 eval(
"self.configure" + svc +
"( handle )")
931 dlls = self.getDlls()
934 elif isinstance(dlls, types.StringType):
937 from __main__
import theApp
939 dlls = filter(
lambda d: d
not in theApp.Dlls, dlls)
952 preLen = Configurable.printHeaderPre
954 Configurable.printHeaderWidth - preLen - 3 - len(title)
956 postLen =
max(preLen, postLen)
957 return indentStr +
"/%s %s %s" % (preLen *
"*", title, postLen *
"*")
961 preLen = Configurable.printHeaderPre
963 Configurable.printHeaderWidth - preLen - 12 - len(title)
965 postLen =
max(preLen, postLen)
966 return indentStr +
"\\%s (End of %s) %s" % (preLen *
"-", title, postLen *
"-")
969 return "{0}({1!r})".
format(self.__class__.__name__, self.
name())
971 def __str__(self, indent=0, headerLastIndentUnit=indentUnit):
974 def _sorted_repr_set(value):
975 """Helper to print sorted set representation"""
976 return "{" + repr(sorted(value))[1:-1] +
"}" if value
else "set()"
978 indentStr = indent * Configurable.indentUnit
983 headerIndent = (indent - 1) * Configurable.indentUnit + headerLastIndentUnit
986 rep = Configurable._printHeader(headerIndent, title)
992 rep += indentStr +
"|-<no properties>" + os.linesep
996 for p
in props.keys():
997 nameWidth =
max(nameWidth, len(p))
998 for p, v
in props.items():
1000 prefix = indentStr +
"|-%-*s" % (nameWidth, p)
1002 if log.isEnabledFor(logging.DEBUG):
1003 if v != Configurable.propertyNoValue:
1004 address =
" @%11s" %
hex(
id(v))
1009 default = defs.get(p)
1010 if v == Configurable.propertyNoValue:
1012 strVal = repr(default)
1016 if hasattr(v,
"getGaudiHandle"):
1017 vv = v.getGaudiHandle()
1020 if isinstance(vv, (GaudiHandle, GaudiHandleArray, DataHandle)):
1023 if hasattr(default,
"toStringProperty"):
1024 strDef = repr(default.toStringProperty())
1026 strDef = repr(default)
1027 if strDef == repr(vv.toStringProperty()):
1029 elif isinstance(vv, set):
1030 strVal = _sorted_repr_set(vv)
1031 strDef = _sorted_repr_set(default)
1034 strDef = repr(default)
1036 line = prefix +
" = " + strVal
1038 if strDef
is not None:
1040 if len(line) + len(strDef) > Configurable.printHeaderWidth:
1045 + (len(prefix) - len(indentStr) - 3) *
" "
1047 line +=
" (default: %s)" % (strDef,)
1049 rep += line + os.linesep
1061 rep += cfg.__str__(indent + 1,
"|=") + os.linesep
1064 rep += Configurable._printFooter(indentStr, title)
1069 Return True is the instance can be "applied".
1070 Always False for plain Configurable instances
1071 (i.e. not ConfigurableUser).
1087 object.__setattr__(obj, self.
__name__, value)
1094 Configurable.__init__(self, name)
1103 return "GenericComponent"
1114 super(ConfigurableGeneric, self).
__setattr__(name, value)
1118 if isinstance(value, Configurable):
1119 self.__dict__[name] = value
1123 if name
not in self._properties:
1125 self._properties[name].__set__(self, value)
1139 "AuditAlgorithms": 0,
1140 "AuditInitialize": 0,
1141 "AuditReinitialize": 0,
1147 super(ConfigurableAlgorithm, self).
__init__(name)
1170 elif rhs
is CFFalse:
1196 return repr(self) == repr(other)
1199 """Return a unique identifier for this object.
1201 As we use the `repr` of this object to check for equality, we use it
1202 here to define uniqueness.
1205 return hash((repr(self),))
1212 "AuditInitialize": 0,
1221 if isinstance(child, ConfigurableAlgTool)
and not child.isPublic():
1222 return copy.deepcopy(child)
1246 "AuditInitialize": 0,
1251 super(ConfigurableAlgTool, self).
__init__(name)
1252 if "." not in self.
_name:
1256 name = name[name.find(
"/") + 1 :]
1280 return pop + Configurable.getPrintTitle(self)
1289 if isinstance(c, ConfigurableAlgTool):
1290 c.setParent(parentName)
1294 name = name[name.rfind(
".") + 1 :]
1315 return parent ==
"ToolSvc"
1326 name = name[name.rfind(
".") + 1 :]
1327 return str(self.
getType() +
"/" + name)
1334 __slots__ = {
"_jobOptName": 0,
"OutputLevel": 0,
"Enable": 1}
1337 super(ConfigurableAuditor, self).
__init__(name)
1339 name = name[name.find(
"/") + 1 :]
1363 "__used_instances__": [],
1375 __used_configurables__ = []
1378 __queried_configurables__ = []
1380 def __init__(self, name=Configurable.DefaultName, _enabled=True, **kwargs):
1381 super(ConfigurableUser, self).
__init__(name)
1382 for n, v
in kwargs.items():
1400 if type(used)
is tuple:
1401 used, used_name = used
1405 if type(used)
is str:
1406 used_class = confDbGetConfigurable(used)
1411 inst = used_class(name=used_name, _enabled=
False)
1412 except AttributeError:
1416 inst = used_class(name=used_name)
1420 if type(queried)
is str:
1421 queried = confDbGetConfigurable(queried)
1422 inst = queried(_enabled=
False)
1423 except AttributeError:
1429 Declare that we are going to modify the Configurable 'other' in our
1430 __apply_configuration__.
1433 if hasattr(other,
"__users__"):
1434 other.__users__.append(self)
1438 Declare that we are going to retrieve property values from the
1439 ConfigurableUser 'other' in our __apply_configuration__.
1441 if not isinstance(other, ConfigurableUser):
1443 "'%s': Cannot make passive use of '%s', it is not a ConfigurableUser"
1444 % (self.
name(), other.name())
1446 other.__addActiveUseOf(self)
1460 Remove this ConfigurableUser instance from the users list of the used
1464 if hasattr(used,
"__users__"):
1465 used.__users__.remove(self)
1469 Propagate the property 'name' (if set) to other configurables (if possible).
1472 propagate to all the entries in __used_configurables__
1473 a configurable instance:
1474 propagate only to it
1475 list of configurable instances:
1476 propagate to all of them.
1480 - if the local property is set, the other property will be overwritten
1481 - local property not set and other set => keep other
1482 - local property not set and other not set => overwrite the default for
1483 ConfigurableUser instances and set the property for Configurables
1488 elif type(others)
not in [list, tuple]:
1494 for other
in [o
for o
in others
if name
in o.__slots__]:
1497 if other.isPropertySet(name):
1499 "Property '%(prop)s' is set in both '%(self)s' and '%(other)s', using '%(self)s.%(prop)s'"
1500 % {
"self": self.
name(),
"other": other.name(),
"prop": name}
1502 other.setProp(name, value)
1504 elif not other.isPropertySet(name):
1505 if isinstance(other, ConfigurableUser):
1506 otherType =
type(other._properties[name].getDefault())
1507 other._properties[name].setDefault(value)
1508 if otherType
in (list, dict, set):
1511 other.setProp(name, otherType(value))
1513 other.setProp(name, value)
1518 Call propagateProperty for each property listed in 'names'.
1519 If 'names' is None, all the properties are propagated.
1523 names = [p
for p
in self.
__slots__ if not p.startswith(
"_")]
1529 Function to be overridden to convert the high level configuration into a
1531 The default implementation calls applyConf, which is the method defined
1532 in some ConfigurableUser implementations.
1538 Function to be overridden to convert the high level configuration into a
1545 Function used to define the name of the private instance of a given class
1547 This method is used when the __used_configurables_property__ declares the
1548 need of a private used configurable without specifying the name.
1550 if type(cls)
is str:
1553 clName = cls.__name__
1554 return "%s_%s" % (self.name(), clName)
1558 Return the used instance with a given name.
1561 if i.name() == name:
1562 if hasattr(i,
"_enabled"):
1567 raise KeyError(name)
1571 Return True is the instance can be "applied".
1577 postConfigActions = []
1582 Add a new callable ('function') to the list of post-configuration actions.
1583 If the callable is already in the list, it is moved to the end of the list.
1584 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1587 postConfigActions.remove(function)
1590 postConfigActions.append(function)
1595 Remove a callable from the list of post-config actions.
1596 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1598 postConfigActions.remove(function)
1601 _appliedConfigurableUsers_ =
False
1606 Call the apply method of all the ConfigurableUser instances respecting the
1607 dependencies. First the C.U.s that are not used by anybody, then the used
1608 ones, when they are not used anymore.
1611 global _appliedConfigurableUsers_, postConfigActions
1612 if _appliedConfigurableUsers_:
1614 _appliedConfigurableUsers_ =
True
1616 def applicableConfUsers():
1618 Generator returning all the configurables that can be applied in the
1619 order in which they can be applied.
1634 for c
in Configurable.allConfigurables.values()
1637 except StopIteration:
1640 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1641 for c
in applicableConfUsers():
1643 log.info(
"applying configuration of %s", c.name())
1645 sys.stderr.write(
"applying %r" % c)
1646 c.__apply_configuration__()
1649 log.info(
"skipping configuration of %s", c.name())
1651 if hasattr(c,
"__detach_used__"):
1658 for c
in Configurable.allConfigurables.values()
1659 if hasattr(c,
"__apply_configuration__")
and c._enabled
and not c._applied
1664 "Detected loop in the ConfigurableUser"
1665 " dependencies: %r" % [c.name()
for c
in leftConfUsers]
1669 unknown = set(Configurable.allConfigurables)
1673 log.debug(
"new configurable created automatically: %s", k)
1675 Configurable.allConfigurables[k].
properties()
1679 for action
in postConfigActions:
1685 Obsolete (buggy) implementation of applyConfigurableUsers(), kept to provide
1686 backward compatibility for configurations that where relying (implicitly) on
1687 bug #103803, or on a specific (non guaranteed) order of execution.
1689 @see applyConfigurableUsers()
1692 global _appliedConfigurableUsers_, postConfigActions
1693 if _appliedConfigurableUsers_:
1695 _appliedConfigurableUsers_ =
True
1697 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1700 for c
in Configurable.allConfigurables.values()
1701 if hasattr(c,
"__apply_configuration__")
1704 while applied
and confUsers:
1708 if hasattr(c,
"__users__")
and c.__users__:
1709 newConfUsers.append(c)
1714 enabled = (
not hasattr(c,
"_enabled"))
or c._enabled
1716 log.info(
"applying configuration of %s", c.name())
1718 sys.stderr.write(
"applying %r" % c)
1719 c.__apply_configuration__()
1722 log.info(
"skipping configuration of %s", c.name())
1723 if hasattr(c,
"__detach_used__"):
1726 confUsers = newConfUsers
1730 "Detected loop in the ConfigurableUser "
1731 " dependencies: %r" % [c.name()
for c
in confUsers]
1735 unknown = set(Configurable.allConfigurables)
1739 log.debug(
"new configurable created automatically: %s", k)
1741 Configurable.allConfigurables[k].
properties()
1745 for action
in postConfigActions:
1751 Function to select all and only the configurables that have to be used in
1752 GaudiPython.AppMgr constructor.
1753 This is needed because in Athena the implementation have to be different (the
1754 configuration is used in a different moment).
1758 for k, v
in Configurable.allConfigurables.items()
1759 if v.getGaudiType() !=
"User"
1765 Clean up all configurations and configurables.
1767 for c
in Configurable.allConfigurables.values():
1768 c.__class__.configurables.clear()
1769 Configurable.allConfigurables.clear()
1772 ConfigurableGeneric.configurables.clear()
1776 from .ProcessJobOptions
import _included_files
1778 for file
in _included_files:
1779 dirname, basname = os.path.split(file)
1780 basname, ext = os.path.splitext(basname)
1781 if basname
in sys.modules:
1782 del sys.modules[basname]
1783 _included_files.clear()
1792 return self.
stack[-1]
1801 name = prefix + str(cnt)
1802 while name
in allConfigurables:
1804 name = prefix + str(cnt)
1808 from Configurables
import Gaudi__Sequencer
1814 if visitee
in (CFTrue, CFFalse):
1815 stack.append(self.
_newSeq(Invert=visitee
is CFFalse))
1816 elif isinstance(visitee, (ControlFlowLeaf, ConfigurableAlgorithm)):
1817 stack.append(visitee)
1818 elif isinstance(visitee, (OrNode, AndNode, OrderedNode)):
1823 ModeOR=isinstance(visitee, OrNode),
1824 ShortCircuit=
not isinstance(visitee, OrderedNode),
1827 elif isinstance(visitee, ignore):
1828 if hasattr(stack[-1],
"IgnoreFilterPassed"):
1829 stack[-1].IgnoreFilterPassed =
True
1832 self.
_newSeq(Members=[stack.pop()], IgnoreFilterPassed=
True)
1834 elif isinstance(visitee, InvertNode):
1835 if hasattr(stack[-1],
"Invert"):
1836 stack[-1].Invert =
True
1838 stack.append(self.
_newSeq(Members=[stack.pop()], Invert=
True))
1843 Convert a control flow expression to nested GaudiSequencers.
1845 if not isinstance(expression, ControlFlowNode):
1847 "ControlFlowNode instance expected, got %s" %
type(expression).__name__
1850 expression.visitNode(visitor)
1851 return visitor.sequence
1856 Helper class to use a ControlFlowNode as an algorithm configurable
1863 if name
in Configurable.allConfigurables:
1864 instance = Configurable.allConfigurables[name]
1865 assert type(instance)
is cls, (
1866 "trying to reuse {0!r} as name of a {1} instance while it"
1868 "already used for an instance of {2}"
1869 ).
format(name, cls.__name__,
type(instance).__name__)
1872 instance = super(SuperAlgorithm, cls).
__new__(cls)
1873 Configurable.allConfigurables[name] = instance
1880 setattr(self, key, kwargs[key])
1905 Instantiate and algorithm of type 'typ' with a name suitable for use
1906 inside a SuperAlgorithm.
1908 name =
"{0}_{1}".
format(self.
name, kwargs.pop(
"name", typ.getType()))
1909 return typ(name, **kwargs)
1912 raise NotImplementedError()
1922 super(SuperAlgorithm, self).
__setattr__(name, value)
1923 if name
in (
"_name",
"graph"):
1927 class PropSetter(object):
1928 def enter(self, node):
1930 setattr(node, name, value)
1931 except (ValueError, AttributeError):
1935 def leave(self, node):
1938 self._visitSubNodes(PropSetter())