19 from inspect
import isclass
21 from GaudiConfig.ControlFlow
import (
56 "ConfigurableAlgorithm",
57 "ConfigurableAlgTool",
58 "ConfigurableAuditor",
59 "ConfigurableService",
67 "appendPostConfigAction",
68 "removePostConfigAction",
74 log = logging.getLogger(
"Configurable")
79 Expand environment variables "data".
80 Data can be string, list, tuple and dictionary. For collection, all the
81 contained strings will be manipulated (recursively).
87 return os.path.expandvars(data)
88 elif typ
in [list, tuple]:
103 Error occurred in the configuration process.
112 class PropertyReference(object):
117 return "@%s" % self.
name
122 refname, refprop = self.
name.rsplit(
".", 1)
123 if refname
in Configurable.allConfigurables:
124 conf = Configurable.allConfigurables[refname]
125 retval = getattr(conf, refprop)
126 if hasattr(retval,
"getFullName"):
127 retval = retval.getFullName()
129 raise NameError(
"name '%s' not found resolving '%s'" % (refname, self))
133 """This function allow transparent integration with
134 Configurable.getValuedProperties.
141 except AttributeError:
150 """Base class for Gaudi components that implement the IProperty interface.
151 Provides most of the boilerplate code, but the actual useful classes
152 are its derived ConfigurableAlgorithm, ConfigurableService, and
153 ConfigurableAlgTool."""
159 propertyNoValue =
"<no value>"
161 printHeaderWidth = 100
174 allConfigurables = {}
175 configurableServices = {}
178 _configurationLocked =
False
181 """To Gaudi, any object with the same type/name is the same object. Hence,
182 this is mimicked in the configuration: instantiating a new Configurable
183 of a type with the same name will return the same instance."""
187 func_defaults = cls.
__init__.__defaults__
191 name = kwargs[
"name"]
192 elif "name" in func_code.co_varnames:
194 index = list(func_code.co_varnames).
index(
"name")
197 name = args[index - 1]
200 name = func_defaults[index - (len(args) + 1)]
205 except (IndexError, TypeError):
207 'no "name" argument while instantiating "%s"' % cls.__name__
212 if hasattr(cls,
"DefaultedName"):
213 name = cls.DefaultedName
216 elif not name
or not isinstance(name, str):
219 "could not retrieve name from %s.__init__ arguments" % cls.__name__
224 if issubclass(cls, ConfigurableAlgTool)
and "." not in name:
225 name =
"ToolSvc." + name
235 if name
in cls.configurables:
236 conf = cls.configurables[name]
238 cls.configurables[conf.getType()] = conf
240 for n, v
in kwargs.items():
245 and "_enabled" not in kwargs
246 and isinstance(conf, ConfigurableUser)
250 setattr(conf,
"_enabled",
True)
254 spos = name.find(
"/")
257 ti_name =
"%s/%s" % (name, name)
258 if ti_name
in cls.configurables:
260 return cls.configurables[ti_name]
265 if i_name == name[spos + 1 :]
and i_name
in cls.configurables:
267 return cls.configurables[i_name]
275 and i_name == name[spos + 1 :]
280 if conf.__class__
is ConfigurableGeneric:
284 newconf = object.__new__(cls)
285 cls.
__init__(newconf, *args, **kwargs)
290 for n
in newconf.__slots__:
292 for n
in conf._properties:
293 if names[n.lower()] != n:
295 "Option '%s' was used for %s, but the correct spelling is '%s'"
296 % (n, name, names[n.lower()])
298 setattr(newconf, names[n.lower()], getattr(conf, n))
299 for n, v
in kwargs.items():
300 setattr(newconf, n, v)
301 cls.configurables[name] = newconf
307 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
309 conf.__class__.__name__,
317 for n, v
in kwargs.items():
322 conf = object.__new__(cls)
326 cls.configurables[name] = conf
328 for base
in cls.__bases__:
329 if base.__name__ ==
"ConfigurableService":
341 klass = self.__class__
344 if klass == Configurable:
346 "%s is an ABC and can not be instantiated" % str(Configurable)
358 for meth, nArgs
in meths.items():
360 f = getattr(klass, meth)
361 except AttributeError:
362 raise NotImplementedError(
363 "%s is missing in class %s" % (meth, str(klass))
367 nargcount = f.__code__.co_argcount
368 fdefaults = f.__defaults__
369 ndefaults = fdefaults
and len(fdefaults)
or 0
370 if not nargcount - ndefaults <= nArgs <= nargcount:
372 "%s.%s requires exactly %d arguments" % (klass, meth, nArgs)
381 if hasattr(self.__class__,
"DefaultedName"):
382 self.
_name = self.__class__.DefaultedName
403 for name, proxy
in self._properties.items():
405 dict[name] = proxy.__get__(self)
406 except AttributeError:
409 dict[
"_Configurable__children"] = self.
__children
410 dict[
"_Configurable__tools"] = self.
__tools
411 dict[
"_name"] = self.
_name
419 from contextlib
import contextmanager
430 for n, v
in dict.items():
442 newconf = object.__new__(self.__class__)
445 for proxy
in self._properties.values():
447 proxy.__set__(newconf, proxy.__get__(self))
448 except AttributeError:
458 if not isinstance(configs, (list, tuple)):
465 if not isinstance(cfg, Configurable):
466 raise TypeError(
"'%s' is not a Configurable" % str(cfg))
471 ccjo = cc.getJobOptName()
473 if c.getJobOptName() == ccjo:
475 "attempt to add a duplicate ... dupe ignored%s",
484 descr.__set__(self, cc)
486 setattr(self, cc.getName(), cc)
487 except AttributeError:
496 if attr
in self._properties:
497 if isinstance(self._properties[attr].__get__(self), DataHandle):
498 return self._properties[attr].__get__(self)
501 if c.getName() == attr:
504 raise AttributeError(
505 "'%s' object has no attribute '%s'" % (self.__class__, attr)
511 "%s: Configuration cannot be modified after the ApplicationMgr has been started."
516 except AttributeError:
517 raise AttributeError(
518 "Configurable '%s' does not have property '%s'."
519 % (self.__class__.__name__, name)
526 prop = self._properties[attr]
527 prop.__delete__(self)
528 prop.__set__(self, prop.default)
538 if c.getName() == attr:
543 del self.__dict__[attr]
544 except (AttributeError, KeyError):
551 if not isinstance(items, (list, 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 isinstance(value, (list, set, tuple)):
715 if hasattr(i,
"getFullName"):
716 new_value.append(i.getFullName())
719 value =
type(value)(new_value)
720 elif isinstance(value, dict):
723 if hasattr(value[i],
"getFullName"):
726 new_value[i] = value[i]
745 for k, v
in cls._properties.items():
746 if k
not 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, set, DataHandle, GaudiHandleArray)):
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 isinstance(value, (str, list, dict, tuple, set)):
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 isinstance(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):
975 def _sorted_repr_set(value):
976 """Helper to print sorted set representation"""
977 return "{" + repr(sorted(value))[1:-1] +
"}" if value
else "set()"
979 indentStr = indent * Configurable.indentUnit
984 headerIndent = (indent - 1) * Configurable.indentUnit + headerLastIndentUnit
987 rep = Configurable._printHeader(headerIndent, title)
993 rep += indentStr +
"|-<no properties>" + os.linesep
997 for p
in props.keys():
998 nameWidth = max(nameWidth, len(p))
999 for p, v
in props.items():
1001 prefix = indentStr +
"|-%-*s" % (nameWidth, p)
1003 if log.isEnabledFor(logging.DEBUG):
1004 if v != Configurable.propertyNoValue:
1005 address =
" @%11s" %
hex(
id(v))
1010 default = defs.get(p)
1011 if v == Configurable.propertyNoValue:
1013 strVal = repr(default)
1017 if hasattr(v,
"getGaudiHandle"):
1018 vv = v.getGaudiHandle()
1021 if isinstance(vv, (GaudiHandle, GaudiHandleArray, DataHandle)):
1024 if hasattr(default,
"toStringProperty"):
1025 strDef = repr(default.toStringProperty())
1027 strDef = repr(default)
1028 if strDef == repr(vv.toStringProperty()):
1030 elif isinstance(vv, set):
1031 strVal = _sorted_repr_set(vv)
1032 strDef = _sorted_repr_set(default)
1035 strDef = repr(default)
1037 line = prefix +
" = " + strVal
1039 if strDef
is not None:
1041 if len(line) + len(strDef) > Configurable.printHeaderWidth:
1046 + (len(prefix) - len(indentStr) - 3) *
" "
1048 line +=
" (default: %s)" % (strDef,)
1050 rep += line + os.linesep
1062 rep += cfg.__str__(indent + 1,
"|=") + os.linesep
1065 rep += Configurable._printFooter(indentStr, title)
1070 Return True is the instance can be "applied".
1071 Always False for plain Configurable instances
1072 (i.e. not ConfigurableUser).
1088 object.__setattr__(obj, self.
__name__, value)
1095 Configurable.__init__(self, name)
1104 return "GenericComponent"
1115 super(ConfigurableGeneric, self).
__setattr__(name, value)
1119 if isinstance(value, Configurable):
1120 self.__dict__[name] = value
1124 if name
not in self._properties:
1126 self._properties[name].__set__(self, value)
1140 "AuditAlgorithms": 0,
1141 "AuditInitialize": 0,
1142 "AuditReinitialize": 0,
1148 super(ConfigurableAlgorithm, self).
__init__(name)
1171 elif rhs
is CFFalse:
1173 return AndNode(self, rhs)
1180 return OrNode(self, rhs)
1183 return InvertNode(self)
1186 return OrderedNode(self, rhs)
1197 return repr(self) == repr(other)
1200 """Return a unique identifier for this object.
1202 As we use the `repr` of this object to check for equality, we use it
1203 here to define uniqueness.
1206 return hash((repr(self),))
1213 "AuditInitialize": 0,
1222 if isinstance(child, ConfigurableAlgTool)
and not child.isPublic():
1223 return copy.deepcopy(child)
1247 "AuditInitialize": 0,
1252 super(ConfigurableAlgTool, self).
__init__(name)
1253 if "." not in self.
_name:
1257 name = name[name.find(
"/") + 1 :]
1281 return pop + Configurable.getPrintTitle(self)
1290 if isinstance(c, ConfigurableAlgTool):
1291 c.setParent(parentName)
1295 name = name[name.rfind(
".") + 1 :]
1316 return parent ==
"ToolSvc"
1327 name = name[name.rfind(
".") + 1 :]
1328 return str(self.
getType() +
"/" + name)
1335 __slots__ = {
"_jobOptName": 0,
"OutputLevel": 0,
"Enable": 1}
1338 super(ConfigurableAuditor, self).
__init__(name)
1340 name = name[name.find(
"/") + 1 :]
1364 "__used_instances__": [],
1376 __used_configurables__ = []
1379 __queried_configurables__ = []
1381 def __init__(self, name=Configurable.DefaultName, _enabled=True, **kwargs):
1382 super(ConfigurableUser, self).
__init__(name)
1383 for n, v
in kwargs.items():
1401 if isinstance(used, tuple):
1402 used, used_name = used
1406 if isinstance(used, str):
1407 used_class = confDbGetConfigurable(used)
1412 inst = used_class(name=used_name, _enabled=
False)
1413 except AttributeError:
1417 inst = used_class(name=used_name)
1421 if isinstance(queried, str):
1422 queried = confDbGetConfigurable(queried)
1423 inst = queried(_enabled=
False)
1424 except AttributeError:
1430 Declare that we are going to modify the Configurable 'other' in our
1431 __apply_configuration__.
1434 if hasattr(other,
"__users__"):
1435 other.__users__.append(self)
1439 Declare that we are going to retrieve property values from the
1440 ConfigurableUser 'other' in our __apply_configuration__.
1442 if not isinstance(other, ConfigurableUser):
1444 "'%s': Cannot make passive use of '%s', it is not a ConfigurableUser"
1445 % (self.
name(), other.name())
1447 other.__addActiveUseOf(self)
1461 Remove this ConfigurableUser instance from the users list of the used
1465 if hasattr(used,
"__users__"):
1466 used.__users__.remove(self)
1470 Propagate the property 'name' (if set) to other configurables (if possible).
1473 propagate to all the entries in __used_configurables__
1474 a configurable instance:
1475 propagate only to it
1476 list of configurable instances:
1477 propagate to all of them.
1481 - if the local property is set, the other property will be overwritten
1482 - local property not set and other set => keep other
1483 - local property not set and other not set => overwrite the default for
1484 ConfigurableUser instances and set the property for Configurables
1489 elif type(others)
not in [list, tuple]:
1495 for other
in [o
for o
in others
if name
in o.__slots__]:
1498 if other.isPropertySet(name):
1500 "Property '%(prop)s' is set in both '%(self)s' and '%(other)s', using '%(self)s.%(prop)s'"
1501 % {
"self": self.
name(),
"other": other.name(),
"prop": name}
1503 other.setProp(name, value)
1505 elif not other.isPropertySet(name):
1506 if isinstance(other, ConfigurableUser):
1507 otherType =
type(other._properties[name].getDefault())
1508 other._properties[name].setDefault(value)
1509 if otherType
in (list, dict, set):
1512 other.setProp(name, otherType(value))
1514 other.setProp(name, value)
1519 Call propagateProperty for each property listed in 'names'.
1520 If 'names' is None, all the properties are propagated.
1524 names = [p
for p
in self.
__slots__ if not p.startswith(
"_")]
1530 Function to be overridden to convert the high level configuration into a
1532 The default implementation calls applyConf, which is the method defined
1533 in some ConfigurableUser implementations.
1539 Function to be overridden to convert the high level configuration into a
1546 Function used to define the name of the private instance of a given class
1548 This method is used when the __used_configurables_property__ declares the
1549 need of a private used configurable without specifying the name.
1551 if isinstance(cls, str):
1554 clName = cls.__name__
1555 return "%s_%s" % (self.name(), clName)
1559 Return the used instance with a given name.
1562 if i.name() == name:
1563 if hasattr(i,
"_enabled"):
1568 raise KeyError(name)
1572 Return True is the instance can be "applied".
1578 postConfigActions = []
1583 Add a new callable ('function') to the list of post-configuration actions.
1584 If the callable is already in the list, it is moved to the end of the list.
1585 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1588 postConfigActions.remove(function)
1591 postConfigActions.append(function)
1596 Remove a callable from the list of post-config actions.
1597 The list is directly accessible as 'GaudiKernel.Configurable.postConfigActions'.
1599 postConfigActions.remove(function)
1602 _appliedConfigurableUsers_ =
False
1607 Call the apply method of all the ConfigurableUser instances respecting the
1608 dependencies. First the C.U.s that are not used by anybody, then the used
1609 ones, when they are not used anymore.
1612 global _appliedConfigurableUsers_, postConfigActions
1613 if _appliedConfigurableUsers_:
1615 _appliedConfigurableUsers_ =
True
1617 def applicableConfUsers():
1619 Generator returning all the configurables that can be applied in the
1620 order in which they can be applied.
1635 for c
in Configurable.allConfigurables.values()
1638 except StopIteration:
1641 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1642 for c
in applicableConfUsers():
1644 log.info(
"applying configuration of %s", c.name())
1646 sys.stderr.write(
"applying %r" % c)
1647 c.__apply_configuration__()
1650 log.info(
"skipping configuration of %s", c.name())
1652 if hasattr(c,
"__detach_used__"):
1659 for c
in Configurable.allConfigurables.values()
1660 if hasattr(c,
"__apply_configuration__")
and c._enabled
and not c._applied
1665 "Detected loop in the ConfigurableUser"
1666 " dependencies: %r" % [c.name()
for c
in leftConfUsers]
1670 unknown = set(Configurable.allConfigurables)
1674 log.debug(
"new configurable created automatically: %s", k)
1676 Configurable.allConfigurables[k].
properties()
1680 for action
in postConfigActions:
1686 Obsolete (buggy) implementation of applyConfigurableUsers(), kept to provide
1687 backward compatibility for configurations that where relying (implicitly) on
1688 bug #103803, or on a specific (non guaranteed) order of execution.
1690 @see applyConfigurableUsers()
1693 global _appliedConfigurableUsers_, postConfigActions
1694 if _appliedConfigurableUsers_:
1696 _appliedConfigurableUsers_ =
True
1698 debugApplyOrder =
"GAUDI_DUBUG_CONF_USER" in os.environ
1701 for c
in Configurable.allConfigurables.values()
1702 if hasattr(c,
"__apply_configuration__")
1705 while applied
and confUsers:
1709 if hasattr(c,
"__users__")
and c.__users__:
1710 newConfUsers.append(c)
1715 enabled = (
not hasattr(c,
"_enabled"))
or c._enabled
1717 log.info(
"applying configuration of %s", c.name())
1719 sys.stderr.write(
"applying %r" % c)
1720 c.__apply_configuration__()
1723 log.info(
"skipping configuration of %s", c.name())
1724 if hasattr(c,
"__detach_used__"):
1727 confUsers = newConfUsers
1731 "Detected loop in the ConfigurableUser "
1732 " dependencies: %r" % [c.name()
for c
in confUsers]
1736 unknown = set(Configurable.allConfigurables)
1740 log.debug(
"new configurable created automatically: %s", k)
1742 Configurable.allConfigurables[k].
properties()
1746 for action
in postConfigActions:
1752 Function to select all and only the configurables that have to be used in
1753 GaudiPython.AppMgr constructor.
1754 This is needed because in Athena the implementation have to be different (the
1755 configuration is used in a different moment).
1759 for k, v
in Configurable.allConfigurables.items()
1760 if v.getGaudiType() !=
"User"
1766 Clean up all configurations and configurables.
1768 for c
in Configurable.allConfigurables.values():
1769 c.__class__.configurables.clear()
1770 Configurable.allConfigurables.clear()
1773 ConfigurableGeneric.configurables.clear()
1777 from .ProcessJobOptions
import _included_files
1779 for file
in _included_files:
1780 dirname, basname = os.path.split(file)
1781 basname, ext = os.path.splitext(basname)
1782 if basname
in sys.modules:
1783 del sys.modules[basname]
1784 _included_files.clear()
1793 return self.
stack[-1]
1802 name = prefix + str(cnt)
1803 while name
in allConfigurables:
1805 name = prefix + str(cnt)
1809 from Configurables
import Gaudi__Sequencer
1815 if visitee
in (CFTrue, CFFalse):
1816 stack.append(self.
_newSeq(Invert=visitee
is CFFalse))
1817 elif isinstance(visitee, (ControlFlowLeaf, ConfigurableAlgorithm)):
1818 stack.append(visitee)
1819 elif isinstance(visitee, (OrNode, AndNode, OrderedNode)):
1824 ModeOR=isinstance(visitee, OrNode),
1825 ShortCircuit=
not isinstance(visitee, OrderedNode),
1828 elif isinstance(visitee, ignore):
1829 if hasattr(stack[-1],
"IgnoreFilterPassed"):
1830 stack[-1].IgnoreFilterPassed =
True
1833 self.
_newSeq(Members=[stack.pop()], IgnoreFilterPassed=
True)
1835 elif isinstance(visitee, InvertNode):
1836 if hasattr(stack[-1],
"Invert"):
1837 stack[-1].Invert =
True
1839 stack.append(self.
_newSeq(Members=[stack.pop()], Invert=
True))
1844 Convert a control flow expression to nested GaudiSequencers.
1846 if not isinstance(expression, ControlFlowNode):
1848 "ControlFlowNode instance expected, got %s" %
type(expression).__name__
1851 expression.visitNode(visitor)
1852 return visitor.sequence
1857 Helper class to use a ControlFlowNode as an algorithm configurable
1864 if name
in Configurable.allConfigurables:
1865 instance = Configurable.allConfigurables[name]
1866 assert type(instance)
is cls, (
1867 "trying to reuse {0!r} as name of a {1} instance while it"
1869 "already used for an instance of {2}"
1870 ).
format(name, cls.__name__,
type(instance).__name__)
1873 instance = super(SuperAlgorithm, cls).
__new__(cls)
1874 Configurable.allConfigurables[name] = instance
1881 setattr(self, key, kwargs[key])
1906 Instantiate and algorithm of type 'typ' with a name suitable for use
1907 inside a SuperAlgorithm.
1909 name =
"{0}_{1}".
format(self.
name, kwargs.pop(
"name", typ.getType()))
1910 return typ(name, **kwargs)
1913 raise NotImplementedError()
1920 self.
graph.visitNode(visitor)
1923 super(SuperAlgorithm, self).
__setattr__(name, value)
1924 if name
in (
"_name",
"graph"):
1928 class PropSetter(object):
1929 def enter(self, node):
1931 setattr(node, name, value)
1932 except (ValueError, AttributeError):
1936 def leave(self, node):
1939 self._visitSubNodes(PropSetter())