14 from __future__
import absolute_import
21 from inspect
import isclass
52 "ConfigurableAlgorithm",
53 "ConfigurableAlgTool",
54 "ConfigurableAuditor",
55 "ConfigurableService",
63 "appendPostConfigAction",
64 "removePostConfigAction",
70 log = logging.getLogger(
"Configurable")
75 Expand environment variables "data".
76 Data can be string, list, tuple and dictionary. For collection, all the
77 contained strings will be manipulated (recursively).
83 return os.path.expandvars(data)
84 elif typ
in [list, tuple]:
99 Error occurred in the configuration process.
108 class PropertyReference(object):
113 return "@%s" % self.
name
118 refname, refprop = self.
name.rsplit(
".", 1)
119 if refname
in Configurable.allConfigurables:
120 conf = Configurable.allConfigurables[refname]
121 retval = getattr(conf, refprop)
122 if hasattr(retval,
"getFullName"):
123 retval = retval.getFullName()
125 raise NameError(
"name '%s' not found resolving '%s'" % (refname, self))
129 """This function allow transparent integration with
130 Configurable.getValuedProperties.
137 except AttributeError:
146 """Base class for Gaudi components that implement the IProperty interface.
147 Provides most of the boilerplate code, but the actual useful classes
148 are its derived ConfigurableAlgorithm, ConfigurableService, and
149 ConfigurableAlgTool."""
155 propertyNoValue =
"<no value>"
157 printHeaderWidth = 100
170 allConfigurables = {}
171 configurableServices = {}
174 _configurationLocked =
False
177 """To Gaudi, any object with the same type/name is the same object. Hence,
178 this is mimicked in the configuration: instantiating a new Configurable
179 of a type with the same name will return the same instance."""
182 func_code = six.get_function_code(cls.
__init__)
183 func_defaults = six.get_function_defaults(cls.
__init__)
187 name = kwargs[
"name"]
188 elif "name" in func_code.co_varnames:
190 index = list(func_code.co_varnames).index(
"name")
193 name = args[index - 1]
196 name = func_defaults[index - (len(args) + 1)]
201 except (IndexError, TypeError):
203 'no "name" argument while instantiating "%s"' % cls.__name__
208 if hasattr(cls,
"DefaultedName"):
209 name = cls.DefaultedName
212 elif not name
or type(name) != str:
215 "could not retrieve name from %s.__init__ arguments" % cls.__name__
220 if issubclass(cls, ConfigurableAlgTool)
and "." not in name:
221 name =
"ToolSvc." + name
231 if name
in cls.configurables:
232 conf = cls.configurables[name]
234 cls.configurables[conf.getType()] = conf
236 for n, v
in kwargs.items():
241 and not "_enabled" in kwargs
242 and isinstance(conf, ConfigurableUser)
246 setattr(conf,
"_enabled",
True)
250 spos = name.find(
"/")
253 ti_name =
"%s/%s" % (name, name)
254 if ti_name
in cls.configurables:
256 return cls.configurables[ti_name]
261 if i_name == name[spos + 1 :]
and i_name
in cls.configurables:
263 return cls.configurables[i_name]
271 and i_name == name[spos + 1 :]
276 if conf.__class__
is ConfigurableGeneric:
280 newconf = object.__new__(cls)
281 cls.
__init__(newconf, *args, **kwargs)
286 for n
in newconf.__slots__:
288 for n
in conf._properties:
289 if names[n.lower()] != n:
291 "Option '%s' was used for %s, but the correct spelling is '%s'"
292 % (n, name, names[n.lower()])
294 setattr(newconf, names[n.lower()], getattr(conf, n))
295 for n, v
in kwargs.items():
296 setattr(newconf, n, v)
297 cls.configurables[name] = newconf
303 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
305 conf.__class__.__name__,
313 for n, v
in kwargs.items():
318 conf = object.__new__(cls)
322 cls.configurables[name] = conf
324 for base
in cls.__bases__:
325 if base.__name__ ==
"ConfigurableService":
337 klass = self.__class__
340 if klass == Configurable:
342 "%s is an ABC and can not be instantiated" % str(Configurable)
354 for meth, nArgs
in meths.items():
356 f = six.get_unbound_function(getattr(klass, meth))
357 except AttributeError:
358 raise NotImplementedError(
359 "%s is missing in class %s" % (meth, str(klass))
363 nargcount = six.get_function_code(f).co_argcount
364 fdefaults = six.get_function_defaults(f)
365 ndefaults = fdefaults
and len(fdefaults)
or 0
366 if not nargcount - ndefaults <= nArgs <= nargcount:
368 "%s.%s requires exactly %d arguments" % (klass, meth, nArgs)
377 if hasattr(self.__class__,
"DefaultedName"):
378 self.
_name = self.__class__.DefaultedName
399 for name, proxy
in self._properties.
items():
401 dict[name] = proxy.__get__(self)
402 except AttributeError:
405 dict[
"_Configurable__children"] = self.
__children
406 dict[
"_Configurable__tools"] = self.
__tools
407 dict[
"_name"] = self.
_name
415 from contextlib
import contextmanager
426 for n, v
in dict.items():
438 newconf = object.__new__(self.__class__)
441 for proxy
in self._properties.values():
443 proxy.__set__(newconf, proxy.__get__(self))
444 except AttributeError:
454 if not type(configs)
in (list, tuple):
461 if not isinstance(cfg, Configurable):
462 raise TypeError(
"'%s' is not a Configurable" % str(cfg))
467 ccjo = cc.getJobOptName()
469 if c.getJobOptName() == ccjo:
471 "attempt to add a duplicate ... dupe ignored%s",
480 descr.__set__(self, cc)
482 setattr(self, cc.getName(), cc)
483 except AttributeError:
493 if attr
in self._properties:
494 if isinstance(self._properties[attr].__get__(self), DataHandle):
495 return self._properties[attr].__get__(self)
498 if c.getName() == attr:
501 raise AttributeError(
502 "'%s' object has no attribute '%s'" % (self.__class__, attr)
508 "%s: Configuration cannot be modified after the ApplicationMgr has been started."
513 except AttributeError:
514 raise AttributeError(
515 "Configurable '%s' does not have property '%s'."
516 % (self.__class__.__name__, name)
523 prop = self._properties[attr]
524 prop.__delete__(self)
525 prop.__set__(self, prop.default)
535 if c.getName() == attr:
540 del self.__dict__[attr]
541 except (AttributeError, KeyError):
548 __nonzero__ = __bool__
551 if type(items) != list
and type(items) != tuple:
561 return copy.deepcopy(child)
575 if hasattr(cc,
"setParent")
and parent:
578 except RuntimeError
as e:
580 log.error(str(e) +
"%s", error_explanation)
581 ccbd = cc.configurables[cc.getJobOptName()]
584 for proxy
in self._properties.values():
585 if cc
in proxy.history:
586 proxy.__set__(ccbd, proxy.__get__(cc))
599 log.error(
"children() is deprecated, use getChildren() instead for consistency")
601 "getChildren() returns a copy; to add a child, use 'parent += child'%s",
607 """Get all (private) configurable children, both explicit ones (added with +=)
608 and the ones in the private GaudiHandle properties"""
611 for proxy
in self._properties.values():
613 c = proxy.__get__(self)
614 except AttributeError:
617 if isinstance(c, Configurable)
and not c.isPublic():
619 elif isinstance(c, GaudiHandle):
621 conf = c.configurable
622 except AttributeError:
625 if not conf.isPublic():
627 elif isinstance(c, GaudiHandleArray):
631 if isinstance(ci, Configurable):
635 conf = ci.configurable
636 except AttributeError:
648 elems.append(c.getFullName())
653 if not hasattr(self,
"_initok")
or not self.
_initok:
656 "Configurable.__init__ not called in %s override"
657 % self.__class__.__name__
672 handle = self.getHandle()
674 log.debug(
"no handle for %s: not transporting properties", self.
_name)
678 for name
in self._properties.
keys():
679 if hasattr(self, name):
680 setattr(handle, name, getattr(self, name))
687 for name, proxy
in self._properties.
items():
689 props[name] = proxy.__get__(self)
690 except AttributeError:
691 props[name] = Configurable.propertyNoValue
696 """Get all properties with their description string as { name : (value, desc) }."""
698 for name, proxy
in self._properties.
items():
700 props[name] = (proxy.__get__(self), proxy.__doc__)
701 except AttributeError:
702 props[name] = (Configurable.propertyNoValue, proxy.__doc__)
707 for name, proxy
in self._properties.
items():
709 value = proxy.__get__(self)
710 if hasattr(value,
"getFullName"):
711 value = value.getFullName()
712 elif type(value)
in [list, tuple]:
715 if hasattr(i,
"getFullName"):
716 new_value.append(i.getFullName())
719 value =
type(value)(new_value)
720 elif type(value)
is dict:
723 if hasattr(value[i],
"getFullName"):
726 new_value[i] = value[i]
745 for k, v
in cls._properties.
items():
746 if not k
in c.__dict__
and hasattr(v,
"default"):
747 c.__dict__[k] = v.default
760 if name
in c.__dict__:
761 return c.__dict__[name]
765 v = cls._properties[name]
766 if hasattr(v,
"default"):
774 """Returns the value of the given property."""
775 if hasattr(self, name):
776 return getattr(self, name)
781 """Set the value of a given property"""
782 return setattr(self, name, value)
785 """Tell if the property 'name' has been set or not.
787 Because of a problem with list and dictionary properties, in those cases
788 if the value is equal to the default, the property is considered as not
791 if not hasattr(self, name):
794 if isinstance(default, (list, dict, DataHandle)):
795 value = getattr(self, name)
796 return value != default
817 "jobOptName() is deprecated, use getJobOptName() instead for consistency%s",
832 if log.isEnabledFor(logging.DEBUG):
840 def clone(self, name=None, **kwargs):
842 if hasattr(self,
"DefaultedName"):
843 name = self.DefaultedName
845 name = self.getType()
847 newconf = Configurable.__new__(self.__class__, name)
848 self.__class__.
__init__(newconf, name)
850 for proxy
in self._properties.values():
852 value = proxy.__get__(self)
853 if type(value)
in [str, list, dict, tuple]:
855 value =
type(value)(value)
856 proxy.__set__(newconf, value)
857 except AttributeError:
860 for c
in self.__children:
863 for n, t
in self.__tools.
items():
864 newconf.addTool(t, n)
866 for name, value
in kwargs.items():
867 setattr(newconf, name, value)
873 dot = fullname.find(
".")
875 parentname = fullname[:dot]
876 longname = fullname[dot + 1 :]
880 dot = longname.find(
".")
882 name = longname[:dot]
885 return parentname, name, longname
888 if isclass(tool)
and issubclass(tool, ConfigurableAlgTool):
892 elif isinstance(tool, ConfigurableAlgTool):
894 name = tool.splitName()[1]
895 priv_tool = tool.clone(self.
getName() +
"." + name)
898 classname = tool.__name__
900 classname =
type(tool).__name__
902 "addTool requires AlgTool configurable. Got %s type" % classname
907 setattr(self, name, self.
__tools[name])
923 handle = __main__.Service(svc)
928 if hasattr(self,
"configure" + svc):
929 eval(
"self.configure" + svc +
"( handle )")
932 dlls = self.getDlls()
935 elif type(dlls) == types.StringType:
938 from __main__
import theApp
940 dlls = filter(
lambda d: d
not in theApp.Dlls, dlls)
953 preLen = Configurable.printHeaderPre
955 Configurable.printHeaderWidth - preLen - 3 - len(title)
957 postLen =
max(preLen, postLen)
958 return indentStr +
"/%s %s %s" % (preLen *
"*", title, postLen *
"*")
962 preLen = Configurable.printHeaderPre
964 Configurable.printHeaderWidth - preLen - 12 - len(title)
966 postLen =
max(preLen, postLen)
967 return indentStr +
"\\%s (End of %s) %s" % (preLen *
"-", title, postLen *
"-")
970 return "{0}({1!r})".
format(self.__class__.__name__, self.
name())
972 def __str__(self, indent=0, headerLastIndentUnit=indentUnit):
974 indentStr = indent * Configurable.indentUnit
979 headerIndent = (indent - 1) * Configurable.indentUnit + headerLastIndentUnit
982 rep = Configurable._printHeader(headerIndent, title)
988 rep += indentStr +
"|-<no properties>" + os.linesep
992 for p
in props.keys():
993 nameWidth =
max(nameWidth, len(p))
994 for p, v
in props.items():
996 prefix = indentStr +
"|-%-*s" % (nameWidth, p)
998 if log.isEnabledFor(logging.DEBUG):
999 if v != Configurable.propertyNoValue:
1000 address =
" @%11s" %
hex(id(v))
1005 default = defs.get(p)
1006 if v == Configurable.propertyNoValue:
1008 strVal = repr(default)
1012 if hasattr(v,
"getGaudiHandle"):
1013 vv = v.getGaudiHandle()
1016 if isinstance(vv, (GaudiHandle, GaudiHandleArray, DataHandle)):
1019 if hasattr(default,
"toStringProperty"):
1020 strDef = repr(default.toStringProperty())
1022 strDef = repr(default)
1023 if strDef == repr(vv.toStringProperty()):
1027 strDef = repr(default)
1029 line = prefix +
" = " + strVal
1031 if strDef
is not None:
1033 if len(line) + len(strDef) > Configurable.printHeaderWidth:
1038 + (len(prefix) - len(indentStr) - 3) *
" "
1040 line +=
" (default: %s)" % (strDef,)
1042 rep += line + os.linesep
1054 rep += cfg.__str__(indent + 1,
"|=") + os.linesep
1057 rep += Configurable._printFooter(indentStr, title)
1062 Return True is the instance can be "applied".
1063 Always False for plain Configurable instances
1064 (i.e. not ConfigurableUser).
1080 object.__setattr__(obj, self.
__name__, value)
1087 Configurable.__init__(self, name)
1096 return "GenericComponent"
1107 super(ConfigurableGeneric, self).
__setattr__(name, value)
1111 if isinstance(value, Configurable):
1112 self.__dict__[name] = value
1116 if not name
in self._properties:
1118 self._properties[name].__set__(self, value)
1132 "AuditAlgorithms": 0,
1133 "AuditInitialize": 0,
1134 "AuditReinitialize": 0,
1140 super(ConfigurableAlgorithm, self).
__init__(name)
1161 elif rhs
is CFFalse:
1187 return repr(self) == repr(other)
1190 """Return a unique identifier for this object.
1192 As we use the `repr` of this object to check for equality, we use it
1193 here to define uniqueness.
1196 return hash((repr(self),))
1203 "AuditInitialize": 0,
1212 if isinstance(child, ConfigurableAlgTool)
and not child.isPublic():
1213 return copy.deepcopy(child)
1218 return iService(self.
_name)
1237 "AuditInitialize": 0,
1242 super(ConfigurableAlgTool, self).
__init__(name)
1243 if "." not in self.
_name:
1247 name = name[name.find(
"/") + 1 :]
1269 return pop + Configurable.getPrintTitle(self)
1278 if isinstance(c, ConfigurableAlgTool):
1279 c.setParent(parentName)
1283 name = name[name.rfind(
".") + 1 :]
1304 return parent ==
"ToolSvc"
1315 name = name[name.rfind(
".") + 1 :]
1316 return str(self.
getType() +
"/" + name)
1323 __slots__ = {
"_jobOptName": 0,
"OutputLevel": 0,
"Enable": 1}
1326 super(ConfigurableAuditor, self).
__init__(name)
1328 name = name[name.find(
"/") + 1 :]
1350 "__used_instances__": [],
1362 __used_configurables__ = []
1365 __queried_configurables__ = []
1367 def __init__(self, name=Configurable.DefaultName, _enabled=True, **kwargs):
1368 super(ConfigurableUser, self).
__init__(name)
1369 for n, v
in kwargs.items():
1387 if type(used)
is tuple:
1388 used, used_name = used
1392 if type(used)
is str:
1393 used_class = confDbGetConfigurable(used)
1398 inst = used_class(name=used_name, _enabled=
False)
1399 except AttributeError:
1403 inst = used_class(name=used_name)
1407 if type(queried)
is str:
1408 queried = confDbGetConfigurable(queried)
1409 inst = queried(_enabled=
False)
1410 except AttributeError:
1416 Declare that we are going to modify the Configurable 'other' in our
1417 __apply_configuration__.
1420 if hasattr(other,
"__users__"):
1421 other.__users__.append(self)
1425 Declare that we are going to retrieve property values from the
1426 ConfigurableUser 'other' in our __apply_configuration__.
1428 if not isinstance(other, ConfigurableUser):
1430 "'%s': Cannot make passive use of '%s', it is not a ConfigurableUser"
1431 % (self.
name(), other.name())
1433 other.__addActiveUseOf(self)
1447 Remove this ConfigurableUser instance from the users list of the used
1451 if hasattr(used,
"__users__"):
1452 used.__users__.remove(self)
1456 Propagate the property 'name' (if set) to other configurables (if possible).
1459 propagate to all the entries in __used_configurables__
1460 a configurable instance:
1461 propagate only to it
1462 list of configurable instances:
1463 propagate to all of them.
1467 - if the local property is set, the other property will be overwritten
1468 - local property not set and other set => keep other
1469 - local property not set and other not set => overwrite the default for
1470 ConfigurableUser instances and set the property for Configurables
1475 elif type(others)
not in [list, tuple]:
1481 for other
in [o
for o
in others
if name
in o.__slots__]:
1484 if other.isPropertySet(name):
1486 "Property '%(prop)s' is set in both '%(self)s' and '%(other)s', using '%(self)s.%(prop)s'"
1487 % {
"self": self.
name(),
"other": other.name(),
"prop": name}
1489 other.setProp(name, value)
1491 elif not other.isPropertySet(name):
1492 if isinstance(other, ConfigurableUser):
1493 otherType =
type(other._properties[name].getDefault())
1494 other._properties[name].setDefault(value)
1495 if otherType
in [list, dict]:
1498 other.setProp(name, otherType(value))
1500 other.setProp(name, value)
1505 Call propagateProperty for each property listed in 'names'.
1506 If 'names' is None, all the properties are propagated.
1510 names = [p
for p
in self.
__slots__ if not p.startswith(
"_")]
1516 Function to be overridden to convert the high level configuration into a
1518 The default implementation calls applyConf, which is the method defined
1519 in some ConfigurableUser implementations.
1525 Function to be overridden to convert the high level configuration into a
1532 Function used to define the name of the private instance of a given class
1534 This method is used when the __used_configurables_property__ declares the
1535 need of a private used configurable without specifying the name.
1537 if type(cls)
is str:
1540 clName = cls.__name__
1541 return "%s_%s" % (self.name(), clName)
1545 Return the used instance with a given name.
1548 if i.name() == name:
1549 if hasattr(i,
"_enabled"):
1554 raise KeyError(name)
1558 Return True is the instance can be "applied".
1564 postConfigActions = []
1569 Add a new callable ('function') to the list of post-configuration actions.
1570 If the callable is already in the list, it is moved to the end of the list.
1571 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1574 postConfigActions.remove(function)
1577 postConfigActions.append(function)
1582 Remove a callable from the list of post-config actions.
1583 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1585 postConfigActions.remove(function)
1588 _appliedConfigurableUsers_ =
False
1593 Call the apply method of all the ConfigurableUser instances respecting the
1594 dependencies. First the C.U.s that are not used by anybody, then the used
1595 ones, when they are not used anymore.
1598 global _appliedConfigurableUsers_, postConfigActions
1599 if _appliedConfigurableUsers_:
1601 _appliedConfigurableUsers_ =
True
1603 def applicableConfUsers():
1605 Generator returning all the configurables that can be applied in the
1606 order in which they can be applied.
1621 for c
in Configurable.allConfigurables.values()
1624 except StopIteration:
1627 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1628 for c
in applicableConfUsers():
1630 log.info(
"applying configuration of %s", c.name())
1632 sys.stderr.write(
"applying %r" % c)
1633 c.__apply_configuration__()
1636 log.info(
"skipping configuration of %s", c.name())
1638 if hasattr(c,
"__detach_used__"):
1645 for c
in Configurable.allConfigurables.values()
1646 if hasattr(c,
"__apply_configuration__")
and c._enabled
and not c._applied
1651 "Detected loop in the ConfigurableUser"
1652 " dependencies: %r" % [c.name()
for c
in leftConfUsers]
1656 unknown = set(Configurable.allConfigurables)
1660 log.debug(
"new configurable created automatically: %s", k)
1662 Configurable.allConfigurables[k].
properties()
1666 for action
in postConfigActions:
1672 Obsolete (buggy) implementation of applyConfigurableUsers(), kept to provide
1673 backward compatibility for configurations that where relying (implicitly) on
1674 bug #103803, or on a specific (non guaranteed) order of execution.
1676 @see applyConfigurableUsers()
1679 global _appliedConfigurableUsers_, postConfigActions
1680 if _appliedConfigurableUsers_:
1682 _appliedConfigurableUsers_ =
True
1684 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1687 for c
in Configurable.allConfigurables.values()
1688 if hasattr(c,
"__apply_configuration__")
1691 while applied
and confUsers:
1695 if hasattr(c,
"__users__")
and c.__users__:
1696 newConfUsers.append(c)
1701 enabled = (
not hasattr(c,
"_enabled"))
or c._enabled
1703 log.info(
"applying configuration of %s", c.name())
1705 sys.stderr.write(
"applying %r" % c)
1706 c.__apply_configuration__()
1709 log.info(
"skipping configuration of %s", c.name())
1710 if hasattr(c,
"__detach_used__"):
1713 confUsers = newConfUsers
1717 "Detected loop in the ConfigurableUser "
1718 " dependencies: %r" % [c.name()
for c
in confUsers]
1722 unknown = set(Configurable.allConfigurables)
1726 log.debug(
"new configurable created automatically: %s", k)
1728 Configurable.allConfigurables[k].
properties()
1732 for action
in postConfigActions:
1738 Function to select all and only the configurables that have to be used in
1739 GaudiPython.AppMgr constructor.
1740 This is needed because in Athena the implementation have to be different (the
1741 configuration is used in a different moment).
1745 for k, v
in Configurable.allConfigurables.items()
1746 if v.getGaudiType() !=
"User"
1752 Clean up all configurations and configurables.
1754 for c
in Configurable.allConfigurables.values():
1755 c.__class__.configurables.clear()
1756 Configurable.allConfigurables.clear()
1759 ConfigurableGeneric.configurables.clear()
1763 from .ProcessJobOptions
import _included_files
1765 for file
in _included_files:
1766 dirname, basname = os.path.split(file)
1767 basname, ext = os.path.splitext(basname)
1768 if basname
in sys.modules:
1769 del sys.modules[basname]
1770 _included_files.clear()
1779 return self.
stack[-1]
1788 name = prefix + str(cnt)
1789 while name
in allConfigurables:
1791 name = prefix + str(cnt)
1795 from Configurables
import GaudiSequencer
1801 if visitee
in (CFTrue, CFFalse):
1802 stack.append(self.
_newSeq(Invert=visitee
is CFFalse))
1803 elif isinstance(visitee, (ControlFlowLeaf, ConfigurableAlgorithm)):
1804 stack.append(visitee)
1805 elif isinstance(visitee, (OrNode, AndNode, OrderedNode)):
1810 ModeOR=isinstance(visitee, OrNode),
1811 ShortCircuit=
not isinstance(visitee, OrderedNode),
1815 elif isinstance(visitee, ignore):
1816 if hasattr(stack[-1],
"IgnoreFilterPassed"):
1817 stack[-1].IgnoreFilterPassed =
True
1820 self.
_newSeq(Members=[stack.pop()], IgnoreFilterPassed=
True)
1822 elif isinstance(visitee, InvertNode):
1823 if hasattr(stack[-1],
"Invert"):
1824 stack[-1].Invert =
True
1826 stack.append(self.
_newSeq(Members=[stack.pop()], Invert=
True))
1831 Convert a control flow expression to nested GaudiSequencers.
1833 if not isinstance(expression, ControlFlowNode):
1835 "ControlFlowNode instance expected, got %s" %
type(expression).__name__
1838 expression.visitNode(visitor)
1839 return visitor.sequence
1844 Helper class to use a ControlFlowNode as an algorithm configurable
1851 if name
in Configurable.allConfigurables:
1852 instance = Configurable.allConfigurables[name]
1853 assert type(instance)
is cls, (
1854 "trying to reuse {0!r} as name of a {1} instance while it"
1856 "already used for an instance of {2}"
1857 ).
format(name, cls.__name__,
type(instance).__name__)
1860 instance = super(SuperAlgorithm, cls).
__new__(cls)
1861 Configurable.allConfigurables[name] = instance
1868 setattr(self, key, kwargs[key])
1893 Instantiate and algorithm of type 'typ' with a name suitable for use
1894 inside a SuperAlgorithm.
1896 name =
"{0}_{1}".
format(self.
name, kwargs.pop(
"name", typ.getType()))
1897 return typ(name, **kwargs)
1900 raise NotImplementedError()
1910 super(SuperAlgorithm, self).
__setattr__(name, value)
1911 if name
in (
"_name",
"graph"):
1915 class PropSetter(object):
1916 def enter(self, node):
1918 setattr(node, name, value)
1919 except (ValueError, AttributeError):
1923 def leave(self, node):
1926 self._visitSubNodes(PropSetter())