19 from inspect
import isclass
21 from GaudiConfig.ControlFlow
import (
56 "ConfigurableAlgorithm",
57 "ConfigurableAlgTool",
58 "ConfigurableAuditor",
59 "ConfigurableService",
67 "appendPostConfigAction",
68 "removePostConfigAction",
79 log = logging.getLogger(
"Configurable")
84 Expand environment variables "data".
85 Data can be string, list, tuple and dictionary. For collection, all the
86 contained strings will be manipulated (recursively).
92 return os.path.expandvars(data)
93 elif typ
in [list, tuple]:
108 Error occurred in the configuration process.
117 class PropertyReference(object):
122 return "@%s" % self.
name
127 refname, refprop = self.
name.rsplit(
".", 1)
128 if refname
in Configurable.allConfigurables:
129 conf = Configurable.allConfigurables[refname]
130 retval = getattr(conf, refprop)
131 if hasattr(retval,
"getFullName"):
132 retval = retval.getFullName()
134 raise NameError(
"name '%s' not found resolving '%s'" % (refname, self))
138 """This function allow transparent integration with
139 Configurable.getValuedProperties.
146 except AttributeError:
155 """Base class for Gaudi components that implement the IProperty interface.
156 Provides most of the boilerplate code, but the actual useful classes
157 are its derived ConfigurableAlgorithm, ConfigurableService, and
158 ConfigurableAlgTool."""
164 propertyNoValue =
"<no value>"
166 printHeaderWidth = 100
179 allConfigurables = {}
180 configurableServices = {}
183 _configurationLocked =
False
186 """To Gaudi, any object with the same type/name is the same object. Hence,
187 this is mimicked in the configuration: instantiating a new Configurable
188 of a type with the same name will return the same instance."""
192 func_defaults = cls.
__init__.__defaults__
196 name = kwargs[
"name"]
197 elif "name" in func_code.co_varnames:
199 index = list(func_code.co_varnames).
index(
"name")
202 name = args[index - 1]
205 name = func_defaults[index - (len(args) + 1)]
210 except (IndexError, TypeError):
212 'no "name" argument while instantiating "%s"' % cls.__name__
217 if hasattr(cls,
"DefaultedName"):
218 name = cls.DefaultedName
221 elif not name
or not isinstance(name, str):
224 "could not retrieve name from %s.__init__ arguments" % cls.__name__
229 if issubclass(cls, ConfigurableAlgTool)
and "." not in name:
230 name =
"ToolSvc." + name
240 if name
in cls.configurables:
241 conf = cls.configurables[name]
243 cls.configurables[conf.getType()] = conf
245 for n, v
in kwargs.items():
250 and "_enabled" not in kwargs
251 and isinstance(conf, ConfigurableUser)
255 setattr(conf,
"_enabled",
True)
259 spos = name.find(
"/")
262 ti_name =
"%s/%s" % (name, name)
263 if ti_name
in cls.configurables:
265 return cls.configurables[ti_name]
270 if i_name == name[spos + 1 :]
and i_name
in cls.configurables:
272 return cls.configurables[i_name]
280 and i_name == name[spos + 1 :]
285 if conf.__class__
is ConfigurableGeneric:
289 newconf = object.__new__(cls)
290 cls.
__init__(newconf, *args, **kwargs)
295 for n
in newconf.__slots__:
297 for n
in conf._properties:
298 if names[n.lower()] != n:
300 "Option '%s' was used for %s, but the correct spelling is '%s'"
301 % (n, name, names[n.lower()])
303 setattr(newconf, names[n.lower()], getattr(conf, n))
304 for n, v
in kwargs.items():
305 setattr(newconf, n, v)
306 cls.configurables[name] = newconf
312 'attempt to redefine type of "%s" (was: %s, new: %s)%s',
314 conf.__class__.__name__,
322 for n, v
in kwargs.items():
327 conf = object.__new__(cls)
331 cls.configurables[name] = conf
333 for base
in cls.__bases__:
334 if base.__name__ ==
"ConfigurableService":
346 klass = self.__class__
349 if klass == Configurable:
351 "%s is an ABC and can not be instantiated" % str(Configurable)
363 for meth, nArgs
in meths.items():
365 f = getattr(klass, meth)
366 except AttributeError:
367 raise NotImplementedError(
368 "%s is missing in class %s" % (meth, str(klass))
372 nargcount = f.__code__.co_argcount
373 fdefaults = f.__defaults__
374 ndefaults = fdefaults
and len(fdefaults)
or 0
375 if not nargcount - ndefaults <= nArgs <= nargcount:
377 "%s.%s requires exactly %d arguments" % (klass, meth, nArgs)
386 if hasattr(self.__class__,
"DefaultedName"):
387 self.
_name = self.__class__.DefaultedName
408 for name, proxy
in self._properties.items():
410 dict[name] = proxy.__get__(self)
411 except AttributeError:
414 dict[
"_Configurable__children"] = self.
__children
415 dict[
"_Configurable__tools"] = self.
__tools
416 dict[
"_name"] = self.
_name
424 from contextlib
import contextmanager
435 for n, v
in dict.items():
447 newconf = object.__new__(self.__class__)
450 for proxy
in self._properties.values():
452 proxy.__set__(newconf, proxy.__get__(self))
453 except AttributeError:
463 if not isinstance(configs, (list, tuple)):
470 if not isinstance(cfg, Configurable):
471 raise TypeError(
"'%s' is not a Configurable" % str(cfg))
476 ccjo = cc.getJobOptName()
478 if c.getJobOptName() == ccjo:
480 "attempt to add a duplicate ... dupe ignored%s",
489 descr.__set__(self, cc)
491 setattr(self, cc.getName(), cc)
492 except AttributeError:
501 if attr
in self._properties:
502 if isinstance(self._properties[attr].__get__(self), DataHandle):
503 return self._properties[attr].__get__(self)
506 if c.getName() == attr:
509 raise AttributeError(
510 "'%s' object has no attribute '%s'" % (self.__class__, attr)
516 "%s: Configuration cannot be modified after the ApplicationMgr has been started."
521 except AttributeError:
522 raise AttributeError(
523 "Configurable '%s' does not have property '%s'."
524 % (self.__class__.__name__, name)
531 prop = self._properties[attr]
532 prop.__delete__(self)
533 prop.__set__(self, prop.default)
543 if c.getName() == attr:
548 del self.__dict__[attr]
549 except (AttributeError, KeyError):
556 if not isinstance(items, (list, tuple)):
566 return copy.deepcopy(child)
580 if hasattr(cc,
"setParent")
and parent:
583 except RuntimeError
as e:
585 log.error(str(e) +
"%s", error_explanation)
586 ccbd = cc.configurables[cc.getJobOptName()]
589 for proxy
in self._properties.values():
590 if cc
in proxy.history:
591 proxy.__set__(ccbd, proxy.__get__(cc))
604 log.error(
"children() is deprecated, use getChildren() instead for consistency")
606 "getChildren() returns a copy; to add a child, use 'parent += child'%s",
612 """Get all (private) configurable children, both explicit ones (added with +=)
613 and the ones in the private GaudiHandle properties"""
616 for proxy
in self._properties.values():
618 c = proxy.__get__(self)
619 except AttributeError:
622 if isinstance(c, Configurable)
and not c.isPublic():
624 elif isinstance(c, GaudiHandle):
626 conf = c.configurable
627 except AttributeError:
630 if not conf.isPublic():
632 elif isinstance(c, GaudiHandleArray):
636 if isinstance(ci, Configurable):
640 conf = ci.configurable
641 except AttributeError:
653 elems.append(c.getFullName())
658 if not hasattr(self,
"_initok")
or not self.
_initok:
661 "Configurable.__init__ not called in %s override"
662 % self.__class__.__name__
677 handle = self.getHandle()
679 log.debug(
"no handle for %s: not transporting properties", self.
_name)
683 for name
in self._properties.
keys():
684 if hasattr(self, name):
685 setattr(handle, name, getattr(self, name))
692 for name, proxy
in self._properties.items():
694 props[name] = proxy.__get__(self)
695 except AttributeError:
696 props[name] = Configurable.propertyNoValue
701 """Get all properties with their description string as { name : (value, desc) }."""
703 for name, proxy
in self._properties.items():
705 props[name] = (proxy.__get__(self), proxy.__doc__)
706 except AttributeError:
707 props[name] = (Configurable.propertyNoValue, proxy.__doc__)
712 for name, proxy
in self._properties.items():
714 value = proxy.__get__(self)
715 if hasattr(value,
"getFullName"):
716 value = value.getFullName()
717 elif isinstance(value, (list, set, tuple)):
720 if hasattr(i,
"getFullName"):
721 new_value.append(i.getFullName())
724 value =
type(value)(new_value)
725 elif isinstance(value, dict):
728 if hasattr(value[i],
"getFullName"):
731 new_value[i] = value[i]
747 for k, v
in cls._properties.items():
748 if k
not in c.__dict__
and hasattr(v,
"default"):
749 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 "AuditInitialize": 0,
1140 "AuditReinitialize": 0,
1146 super(ConfigurableAlgorithm, self).
__init__(name)
1169 elif rhs
is CFFalse:
1171 return AndNode(self, rhs)
1178 return OrNode(self, rhs)
1181 return InvertNode(self)
1184 return OrderedNode(self, rhs)
1195 return repr(self) == repr(other)
1198 """Return a unique identifier for this object.
1200 As we use the `repr` of this object to check for equality, we use it
1201 here to define uniqueness.
1204 return hash((repr(self),))
1210 "AuditInitialize": 0,
1219 if isinstance(child, ConfigurableAlgTool)
and not child.isPublic():
1220 return copy.deepcopy(child)
1243 "AuditInitialize": 0,
1248 super(ConfigurableAlgTool, self).
__init__(name)
1249 if "." not in self.
_name:
1253 name = name[name.find(
"/") + 1 :]
1277 return pop + Configurable.getPrintTitle(self)
1287 instance = name[name.rfind(
".") + 1 :]
1291 if isinstance(c, ConfigurableAlgTool):
1292 c.setParent(parentName +
"." + instance)
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 isinstance(used, tuple):
1401 used, used_name = used
1405 if isinstance(used, 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 isinstance(queried, 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 isinstance(cls, 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()
1919 self.
graph.visitNode(visitor)
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())