Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:54

0001 from __future__ import absolute_import
0002 import sys
0003 
0004 from builtins import range
0005 from .Mixins import _ConfigureComponent, PrintOptions
0006 from .Mixins import _Labelable, _Unlabelable
0007 from .Mixins import _ValidatingParameterListBase
0008 from .ExceptionHandling import *
0009 from .OrderedSet import OrderedSet
0010 
0011 class _HardDependency(object):
0012     """Information relevant for when a hard dependency,
0013        which uses the * operator, is found"""
0014     def __init__(self, sequenceName, depSet):
0015         self.sequenceName = sequenceName
0016         self.depSet = depSet
0017 
0018 class _Sequenceable(object):
0019     """Denotes an object which can be placed in a sequence"""
0020     def __init__(self):
0021         pass
0022     def __mul__(self,rhs):
0023         return _SequenceCollection(self,rhs)
0024     def __add__(self,rhs):
0025         return _SequenceCollection(self,rhs)
0026     def __invert__(self):
0027         return _SequenceNegation(self)
0028     def _clonesequence(self, lookuptable):
0029         try:
0030             return lookuptable[id(self)]
0031         except:
0032             raise KeyError("no "+str(type(self))+" with id "+str(id(self))+" found")
0033     def resolve(self, processDict,keepIfCannotResolve:bool=False):
0034         return self
0035     def isOperation(self):
0036         """Returns True if the object is an operator (e.g. *,+ or !) type"""
0037         return False
0038     def isLeaf(self):
0039         return False
0040     def _visitSubNodes(self,visitor):
0041         pass
0042     def visitNode(self,visitor):
0043         visitor.enter(self)
0044         self._visitSubNodes(visitor)
0045         visitor.leave(self)
0046     def _appendToCollection(self,collection):
0047         collection.append(self)
0048     def _errorstr(self):
0049         return "A Sequenceable type"
0050 
0051 def _checkIfSequenceable(caller, v):
0052     if not isinstance(v,_Sequenceable):
0053         typename = format_typename(caller)
0054         msg = format_outerframe(2)
0055         msg += "%s only takes arguments of types which are allowed in a sequence, but was given:\n" %typename
0056         msg +=format_typename(v)
0057         msg +="\nPlease remove the problematic object from the argument list"
0058         raise TypeError(msg)
0059 
0060 def _checkIfBooleanLogicSequenceable(caller, v):
0061     if not isinstance(v,_BooleanLogicSequenceable):
0062         typename = format_typename(caller)
0063         msg = format_outerframe(2)
0064         msg += "%s only takes arguments of types which are allowed in a boolean logic sequence, but was given:\n" %typename
0065         msg +=format_typename(v)
0066         msg +="\nPlease remove the problematic object from the argument list"
0067         raise TypeError(msg)
0068 
0069 class _BooleanLogicSequenceable(_Sequenceable):
0070     """Denotes an object which can be used in a boolean logic sequence"""
0071     def __init__(self):
0072         super(_BooleanLogicSequenceable,self).__init__()
0073     def __or__(self,other):
0074         return _BooleanLogicExpression(_BooleanLogicExpression.OR,self,other)
0075     def __and__(self,other):
0076         return _BooleanLogicExpression(_BooleanLogicExpression.AND,self,other)
0077 
0078 
0079 class _BooleanLogicExpression(_BooleanLogicSequenceable):
0080     """Contains the operation of a boolean logic expression"""
0081     OR = 0
0082     AND = 1
0083     def __init__(self,op,left,right):
0084         _checkIfBooleanLogicSequenceable(self,left)
0085         _checkIfBooleanLogicSequenceable(self,right)
0086         self._op = op
0087         self._items = list()
0088         #if either the left or right side are the same kind of boolean expression
0089         # then we can just add their items to our own. This keeps the expression
0090         # tree more compact
0091         if isinstance(left,_BooleanLogicExpression) and left._op == self._op:
0092             self._items.extend(left._items)
0093         else:
0094             self._items.append(left)
0095         if isinstance(right,_BooleanLogicExpression) and right._op == self._op:
0096             self._items.extend(right._items)
0097         else:
0098             self._items.append(right)
0099     def isOperation(self):
0100         return True
0101     def _visitSubNodes(self,visitor):
0102         for i in self._items:
0103             i.visitNode(visitor)
0104     def dumpSequencePython(self, options:PrintOptions=PrintOptions()):
0105         returnValue = ''
0106         join = ''
0107         operatorJoin =self.operatorString()
0108         for m in self._items:
0109             returnValue +=join
0110             join = operatorJoin
0111             if not isinstance(m,_BooleanLogicSequenceLeaf):
0112                 returnValue += '('+m.dumpSequencePython(options)+')'
0113             else:
0114                 returnValue += m.dumpSequencePython(options)
0115         return returnValue
0116     def operatorString(self):
0117         returnValue ='|'
0118         if self._op == self.AND:
0119             returnValue = '&'
0120         return returnValue
0121 
0122 
0123 class _SequenceLeaf(_Sequenceable):
0124     def __init__(self):
0125         pass
0126     def isLeaf(self):
0127         return True
0128 
0129 
0130 class _BooleanLogicSequenceLeaf(_BooleanLogicSequenceable):
0131     def __init__(self):
0132         pass
0133     def isLeaf(self):
0134         return True
0135 
0136 class _SequenceCollection(_Sequenceable):
0137     """Holds representation of the operations without having to use recursion.
0138     Operations are added to the beginning of the list and their operands are
0139     added to the end of the list, with the left added before the right
0140     """
0141     def __init__(self,*seqList):
0142         self._collection = list()
0143         for s in seqList:
0144             _checkIfSequenceable(self,s)
0145             s._appendToCollection(self._collection)
0146     def __mul__(self,rhs):
0147         _checkIfSequenceable(self,rhs)
0148         rhs._appendToCollection(self._collection)
0149         return self
0150     def __add__(self,rhs):
0151         _checkIfSequenceable(self,rhs)
0152         rhs._appendToCollection(self._collection)
0153         return self
0154     def __str__(self):
0155         sep = ''
0156         returnValue = ''
0157         for m in self._collection:
0158             if m is not None:
0159                 returnValue += sep+str(m)
0160                 sep = '+'
0161         return returnValue
0162     def _appendToCollection(self,collection):
0163         collection.extend(self._collection)
0164 
0165     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0166         returnValue = ''
0167         separator = ''
0168         for item in self._collection:
0169             itemDump = item.dumpSequencePython(options)
0170             if itemDump:
0171                 returnValue += (separator + itemDump)
0172                 separator = '+'
0173         return returnValue
0174 
0175     def dumpSequenceConfig(self) -> str:
0176         returnValue = self._collection[0].dumpSequenceConfig()
0177         for m in self._collection[1:]:
0178             returnValue += '&'+m.dumpSequenceConfig()
0179         return returnValue
0180 
0181     def directDependencies(self,sortByType:bool=True):
0182         return findDirectDependencies(self, self._collection,sortByType=sortByType)
0183 
0184     def visitNode(self,visitor):
0185         for m in self._collection:
0186             m.visitNode(visitor)
0187 
0188     def resolve(self, processDict,keepIfCannotResolve:bool=False):
0189         self._collection = [x.resolve(processDict,keepIfCannotResolve) for x in self._collection]
0190         return self
0191 
0192     def index(self,item):
0193         return self._collection.index(item)
0194 
0195     def insert(self,index:int,item):
0196         self._collection.insert(index,item)
0197     def _replaceIfHeldDirectly(self,original,replacement):
0198         didReplace = False
0199         for i in self._collection:
0200             if original == i:
0201                 self._collection[self._collection.index(original)] = replacement
0202                 didReplace = True
0203             elif isinstance(i,_UnarySequenceOperator) and i._has(original):
0204                 didReplace = True
0205                 if replacement is None:
0206                     self._collection[self._collection.index(i)] = None
0207                 else:
0208                     self._collection[self._collection.index(i)] = type(i)(replacement)
0209         if replacement is None:
0210             self._collection = [ i for i in self._collection if i is not None]
0211         return didReplace
0212 
0213 
0214 def findDirectDependencies(element, collection,sortByType:bool=True):
0215     dependencies = []
0216     for item in collection:
0217         # skip null items
0218         if item is None:
0219             continue
0220         # EDFilter, EDProducer, EDAnalyzer, OutputModule
0221         # should check for Modules._Module, but that doesn't seem to work
0222         elif isinstance(item, _SequenceLeaf):
0223             t = 'modules'
0224         # cms.ignore(module), ~(module)
0225         elif isinstance(item, (_SequenceIgnore, _SequenceNegation)):
0226             if isinstance(item._operand, _SequenceCollection):
0227                 dependencies += item.directDependencies(sortByType)
0228                 continue
0229             t = 'modules'
0230         # _SequenceCollection
0231         elif isinstance(item, _SequenceCollection):
0232             dependencies += item.directDependencies(sortByType)
0233             continue
0234         # cms.Sequence
0235         elif isinstance(item, Sequence):
0236             if not item.hasLabel_():
0237                 dependencies += item.directDependencies(sortByType)
0238                 continue
0239             t = 'sequences'
0240         # cms.Task
0241         elif isinstance(item, Task):
0242             if not item.hasLabel_():
0243                 dependencies += item.directDependencies(sortByType)
0244                 continue
0245             t = 'tasks'
0246         # cms.ConditionalTask
0247         elif isinstance(item, ConditionalTask):
0248             if not item.hasLabel_():
0249                 dependencies += item.directDependencies(sortByType)
0250                 continue
0251             t = 'conditionaltasks'
0252         # SequencePlaceholder and TaskPlaceholder do not add an explicit dependency
0253         elif isinstance(item, (SequencePlaceholder, TaskPlaceholder, ConditionalTaskPlaceholder)):
0254             continue
0255         # unsupported elements
0256         else:
0257             sys.stderr.write("Warning: unsupported element '%s' in %s '%s'\n" % (str(item), type(element).__name__, element.label_()))
0258             continue
0259         dependencies.append((t, item.label_()))
0260     if sortByType:
0261         return sorted(set(dependencies), key = lambda t_item: (t_item[0].lower(), t_item[1].lower().replace('_cfi', '')))
0262     else:
0263         return dependencies
0264 
0265 
0266 class _ModuleSequenceType(_ConfigureComponent, _Labelable):
0267     """Base class for classes which define a sequence of modules"""
0268     def __init__(self,*arg, **argv):
0269         self.__dict__["_isFrozen"] = False
0270         self._seq = None
0271         if (len(arg) > 1 and not isinstance(arg[1], _TaskBase)) or (len(arg) > 0 and not isinstance(arg[0],_Sequenceable) and not isinstance(arg[0],_TaskBase)):
0272             typename = format_typename(self)
0273             msg = format_outerframe(2)
0274             msg += "The %s constructor takes zero or one sequenceable argument followed by zero or more arguments of type Task. But the following types are given:\n" %typename
0275             for item,i in zip(arg, range(1,20)):
0276                 try:
0277                     msg += "    %i) %s \n"  %(i, item._errorstr())
0278                 except:
0279                     msg += "    %i) Not sequenceable and not a Task\n" %(i)
0280             if len(arg) > 1 and isinstance(arg[0],_Sequenceable) and isinstance(arg[1], _Sequenceable):
0281                 msg += "Maybe you forgot to combine the sequenceable arguments via '*' or '+'."
0282             raise TypeError(msg)
0283         tasks = arg
0284         if len(arg) > 0 and isinstance(arg[0], _Sequenceable):
0285             self._seq = _SequenceCollection()
0286             arg[0]._appendToCollection(self._seq._collection)
0287             tasks = arg[1:]
0288         self._isModified = False
0289 
0290         self._tasks = OrderedSet()
0291 
0292         if len(tasks) > 0:
0293             self.associate(*tasks)
0294     def associate(self,*tasks):
0295         for task in tasks:
0296             if not isinstance(task, _TaskBase):
0297                 raise TypeError("associate only works with objects of type Task")
0298             self._tasks.add(task)
0299     def isFrozen(self) -> bool:
0300         return self._isFrozen
0301     def setIsFrozen(self):
0302         self._isFrozen = True
0303     def _place(self,name:str,proc):
0304         self._placeImpl(name,proc)
0305     def __imul__(self,rhs):
0306         _checkIfSequenceable(self, rhs)
0307         if self._seq is None:
0308             self.__dict__["_seq"] = _SequenceCollection()
0309         self._seq+=rhs
0310         return self
0311     def __iadd__(self,rhs):
0312         _checkIfSequenceable(self, rhs)
0313         if self._seq is None:
0314             self.__dict__["_seq"] = _SequenceCollection()
0315         self._seq += rhs
0316         return self
0317     def __str__(self):
0318         v = ExpandVisitor(type(self))
0319         self.visit(v)
0320         return v.resultString()
0321 
0322     def dumpConfig(self, options:PrintOptions) -> str:
0323         s = ''
0324         if self._seq is not None:
0325             s = self._seq.dumpSequenceConfig()
0326         return '{'+s+'}\n'
0327 
0328     def dumpPython(self, options:PrintOptions=PrintOptions()) -> str:
0329         """Returns a string which is the python representation of the object"""
0330         s = self.dumpPythonNoNewline(options)
0331         return s + "\n"
0332 
0333     def dumpPythonNoNewline(self, options:PrintOptions=PrintOptions()) -> str:
0334         s=''
0335         if self._seq is not None:
0336             s =self._seq.dumpSequencePython(options)
0337         associationContents = set()
0338         for task in self._tasks:
0339             if task.hasLabel_():
0340                 associationContents.add(_Labelable.dumpSequencePython(task, options))
0341             else:
0342                 associationContents.add(task.dumpPythonNoNewline(options))
0343         for iString in sorted(associationContents):
0344             if s:
0345                 s += ", "
0346             s += iString
0347         if len(associationContents) > 254:
0348             return 'cms.'+type(self).__name__+'(*['+s+'])'
0349         return 'cms.'+type(self).__name__+'('+s+')'
0350 
0351     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0352         """Returns a string which contains the python representation of just the internal sequence"""
0353         # only dump the label, if possible
0354         if self.hasLabel_():
0355             return _Labelable.dumpSequencePython(self, options)
0356         elif len(self._tasks) == 0:
0357             if self._seq is None:
0358                 return ''
0359             s = self._seq.dumpSequencePython(options)
0360             if s:
0361               return '('+s+')'
0362             return ''
0363         return self.dumpPythonNoNewline(options)
0364 
0365     def dumpSequenceConfig(self) -> str:
0366         """Returns a string which contains the old config language representation of just the internal sequence"""
0367         # only dump the label, if possible
0368         if self.hasLabel_():
0369             return _Labelable.dumpSequenceConfig(self)
0370         else:
0371             # dump it verbose
0372             if self._seq is None:
0373                 return ''
0374             return '('+self._seq.dumpSequenceConfig()+')'
0375 
0376     def __repr__(self):
0377         s = ''
0378         if self._seq is not None:
0379            s = str(self._seq)
0380         return "cms."+type(self).__name__+'('+s+')\n'
0381 
0382     def directDependencies(self,sortByType:bool=True):
0383         """Returns the list of modules and other entities that are directly used"""
0384         result = []
0385         if self._seq:
0386           result += self._seq.directDependencies(sortByType=sortByType)
0387         if self._tasks:
0388           result += findDirectDependencies(self, self._tasks,sortByType=sortByType)
0389         return result
0390 
0391     def moduleNames(self):
0392         """Returns a set containing the names of all modules being used"""
0393         result = set()
0394         visitor = NodeNameVisitor(result)
0395         self.visit(visitor)
0396         return result
0397 
0398     def contains(self, mod):
0399         visitor = ContainsModuleVisitor(mod)
0400         self.visit(visitor)
0401         return visitor.result()
0402 
0403     def copy(self):
0404         returnValue =_ModuleSequenceType.__new__(type(self))
0405         if self._seq is not None:
0406             returnValue.__init__(self._seq)
0407         else:
0408             returnValue.__init__()
0409         returnValue._tasks = OrderedSet(self._tasks)
0410         return returnValue
0411 
0412     def copyAndExclude(self,listOfModulesToExclude):
0413         """Returns a copy of the sequence which excludes those module in 'listOfModulesToExclude'"""
0414         # You can exclude instances of these types EDProducer, EDFilter, OutputModule,
0415         # EDAnalyzer, ESSource, ESProducer, Service, Sequence, SequencePlaceholder, Task,
0416         # _SequenceNegation, and _SequenceIgnore.
0417         # Mostly this is very intuitive, but there are some complications in cases
0418         # where objects that contain other objects are involved. See the comments
0419         # for the _MutatingSequenceVisitor.
0420         v = _CopyAndExcludeSequenceVisitor(listOfModulesToExclude)
0421         self.visit(v)
0422         result = self.__new__(type(self))
0423         result.__init__(v.result(self)[0], *v.result(self)[1])
0424         return result
0425     def expandAndClone(self):
0426         # Name of this function is not very good. It makes a shallow copy with all
0427         # the subTasks and subSequences flattened out (removed), but keeping all the
0428         # modules that were in those subSequences and subTasks as well as the top level
0429         # ones. Note this will also remove placeholders so one should probably
0430         # call resolve before using this if the sequence contains any placeholders.
0431         visitor = ExpandVisitor(type(self))
0432         self.visit(visitor)
0433         return visitor.result()
0434     def _postProcessFixup(self,lookuptable):
0435         self._seq = self._seq._clonesequence(lookuptable)
0436         return self
0437     def replace(self, original, replacement):
0438         """Finds all instances of 'original' and substitutes 'replacement' for them.
0439            Returns 'True' if a replacement occurs."""
0440         # This works for either argument being of type EDProducer, EDFilter, OutputModule,
0441         # EDAnalyzer, ESProducer, ESSource, Service, Sequence, SequencePlaceHolder,
0442         # Task, _SequenceNegation, _SequenceIgnore. Although it will fail with a
0443         # raised exception if the replacement actually hits a case where a
0444         # non-Sequenceable object is placed in the sequenced part of a Sequence
0445         # or a type not allowed on a Task is put on a Task.
0446         # There is one special case where we need an explicit check to prevent
0447         # the algorithm from getting confused, either both or neither can be Tasks
0448         #
0449         # Mostly this is very intuitive, but there are some complications in cases
0450         # where objects that contain other objects are involved. See the comments
0451         # for the _MutatingSequenceVisitor.
0452 
0453         if (isinstance(original,Task) != isinstance(replacement,Task)):
0454                raise TypeError("replace only works if both arguments are Tasks or neither")
0455         if (isinstance(original,ConditionalTask) != isinstance(replacement,ConditionalTask)):
0456                raise TypeError("replace only works if both arguments are ConditionalTasks or neither")
0457         v = _CopyAndReplaceSequenceVisitor(original,replacement)
0458         self.visit(v)
0459         if v.didReplace():
0460             self._seq = v.result(self)[0]
0461             if v.result(self)[1]:
0462               self._tasks.clear()
0463               self.associate(*v.result(self)[1])
0464         return v.didReplace()
0465     def _replaceIfHeldDirectly(self,original,replacement):
0466         """Only replaces an 'original' with 'replacement' if 'original' is directly held.
0467             If another Sequence or Task holds 'original' it will not be replaced."""
0468         didReplace = False
0469         if original in self._tasks:
0470             self._tasks.remove(original)
0471             if replacement is not None:
0472                 self._tasks.add(replacement)
0473             didReplace = True
0474         if self._seq is not None:
0475             didReplace |= self._seq._replaceIfHeldDirectly(original,replacement)
0476         return didReplace
0477 
0478 
0479     def index(self,item):
0480         """Returns the index at which the item is found or raises an exception"""
0481         if self._seq is not None:
0482             return self._seq.index(item)
0483         raise ValueError(str(item)+" is not in the sequence")
0484     def insert(self,index,item):
0485         """Inserts the item at the index specified"""
0486         _checkIfSequenceable(self, item)
0487         if self._seq is None:
0488             self.__dict__["_seq"] = _SequenceCollection()
0489         self._seq.insert(index,item)
0490     def remove(self, something):
0491         """Remove the first occurrence of 'something' (a sequence or a module)
0492            Returns 'True' if the module has been removed, False if it was not found"""
0493         # You can remove instances of these types EDProducer, EDFilter, OutputModule,
0494         # EDAnalyzer, ESSource, ESProducer, Service, Sequence, SequencePlaceholder, Task,
0495         # _SequenceNegation, and _SequenceIgnore.
0496         # Mostly this is very intuitive, but there are some complications in cases
0497         # where objects that contain other objects are involved. See the comments
0498         # for the _MutatingSequenceVisitor.
0499         #
0500         # Works very similar to copyAndExclude, there are 2 differences. This changes
0501         # the object itself instead of making a copy and second it only removes
0502         # the first instance of the argument instead of all of them.
0503         v = _CopyAndRemoveFirstSequenceVisitor(something)
0504         self.visit(v)
0505         if v.didRemove():
0506             self._seq = v.result(self)[0]
0507             if v.result(self)[1]:
0508               self._tasks.clear()
0509               self.associate(*v.result(self)[1])
0510         return v.didRemove()
0511     def resolve(self, processDict,keepIfCannotResolve:bool=False):
0512         if self._seq is not None:
0513             self._seq = self._seq.resolve(processDict,keepIfCannotResolve)
0514         for task in self._tasks:
0515             task.resolve(processDict,keepIfCannotResolve)
0516         return self
0517     def __setattr__(self,name:str,value):
0518         if not name.startswith("_"):
0519             raise AttributeError("You cannot set parameters for sequence like objects.")
0520         else:
0521             self.__dict__[name] = value
0522     #def replace(self,old,new):
0523     #"""Find all instances of old and replace with new"""
0524     #def insertAfter(self,which,new):
0525     #"""new will depend on which but nothing after which will depend on new"""
0526     #((a*b)*c)  >> insertAfter(b,N) >> ((a*b)*(N+c))
0527     #def insertBefore(self,which,new):
0528     #"""new will be independent of which"""
0529     #((a*b)*c) >> insertBefore(b,N) >> ((a*(N+b))*c)
0530     #def __contains__(self,item):
0531     #"""returns whether or not 'item' is in the sequence"""
0532     #def modules_(self):
0533     def nameInProcessDesc_(self, myname:str):
0534         return myname
0535     def insertInto(self, parameterSet, myname:str, decoratedList):
0536         parameterSet.addVString(True, myname, decoratedList)
0537     def visit(self,visitor):
0538         """Passes to visitor's 'enter' and 'leave' method each item describing the module sequence.
0539         If the item contains 'sub' items then visitor will see those 'sub' items between the
0540         item's 'enter' and 'leave' calls.
0541         """
0542         if self._seq is not None:
0543             self._seq.visitNode(visitor)
0544         for item in self._tasks:
0545             visitor.enter(item)
0546             item.visit(visitor)
0547             visitor.leave(item)
0548 
0549 class _UnarySequenceOperator(_BooleanLogicSequenceable):
0550     """For ~ and - operators"""
0551     def __init__(self, operand):
0552        self._operand = operand
0553        if isinstance(operand, _ModuleSequenceType):
0554            raise RuntimeError("This operator cannot accept a sequence")
0555        if not isinstance(operand, _Sequenceable):
0556            raise RuntimeError("This operator cannot accept a non sequenceable type")
0557     def __eq__(self, other) -> bool:
0558         # allows replace(~a, b)
0559         return type(self) is type(other) and self._operand==other._operand
0560     def __ne__(self, other) -> bool:
0561         return not self.__eq__(other)
0562     def __hash__(self):
0563         # this definition implies that self._operand MUST NOT be changed after the construction
0564         return hash((type(self), self._operand))
0565     def _findDependencies(self,knownDeps, presentDeps):
0566         self._operand._findDependencies(knownDeps, presentDeps)
0567     def _clonesequence(self, lookuptable):
0568         return type(self)(self._operand._clonesequence(lookuptable))
0569     def _has(self, op) -> bool:
0570         return self._operand == op
0571     def resolve(self, processDict,keepIfCannotResolve=False):
0572         return type(self)(self._operand.resolve(processDict,keepIfCannotResolve))
0573     def isOperation(self) -> bool:
0574         return True
0575     def _visitSubNodes(self,visitor):
0576         self._operand.visitNode(visitor)
0577     def decoration(self) -> str:
0578         self._operand.decoration()
0579     def directDependencies(self,sortByType:bool=True):
0580         return self._operand.directDependencies(sortByType=sortByType)
0581     def label_(self) -> str:
0582         return self._operand.label_()
0583 
0584 class _SequenceNegation(_UnarySequenceOperator):
0585     """Used in the expression tree for a sequence as a stand in for the '!' operator"""
0586     def __init__(self, operand):
0587         super(_SequenceNegation,self).__init__(operand)
0588     def __str__(self) -> str:
0589         return '~%s' %self._operand
0590     def dumpSequenceConfig(self) -> str:
0591         return '!%s' %self._operand.dumpSequenceConfig()
0592     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0593         if self._operand.isOperation():
0594             return '~(%s)' %self._operand.dumpSequencePython(options)
0595         return '~%s' %self._operand.dumpSequencePython(options)
0596     def decoration(self) -> str:
0597         return '!'
0598 
0599 class _SequenceIgnore(_UnarySequenceOperator):
0600     """Used in the expression tree for a sequence as a stand in for the '-' operator"""
0601     def __init__(self, operand):
0602         super(_SequenceIgnore,self).__init__(operand)
0603     def __str__(self) -> str:
0604         return 'ignore(%s)' %self._operand
0605     def dumpSequenceConfig(self) ->str:
0606         return '-%s' %self._operand.dumpSequenceConfig()
0607     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0608         return 'cms.ignore(%s)' %self._operand.dumpSequencePython(options)
0609     def decoration(self) -> str:
0610         return '-'
0611 
0612 class _SequenceWait(_UnarySequenceOperator):
0613     """Used in the expression tree for a sequence as a stand in for the '|' operator"""
0614     def __init__(self, operand):
0615         super(_SequenceWait,self).__init__(operand)
0616     def __str__(self) -> str:
0617         return 'wait(%s)' %self._operand
0618     def dumpSequenceConfig(self) -> str:
0619         return '|%s' %self._operand.dumpSequenceConfig()
0620     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0621         return 'cms.wait(%s)' %self._operand.dumpSequencePython(options)
0622     def decoration(self) -> str:
0623         return '|'
0624 
0625 class _SequenceWaitAndIgnore(_UnarySequenceOperator):
0626     """Used in the expression tree for a sequence as a stand in for the '+' operator"""
0627     def __init__(self, operand):
0628         super(_SequenceWaitAndIgnore,self).__init__(operand)
0629     def __str__(self) -> str:
0630         return 'wait(ignore(%s))' %self._operand
0631     def dumpSequenceConfig(self) -> str:
0632         return '+%s' %self._operand.dumpSequenceConfig()
0633     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
0634         return 'cms.wait(cms.ignore(%s))' %self._operand.dumpSequencePython(options)
0635     def decoration(self) -> str:
0636         return '+'
0637 
0638 def ignore(seq):
0639     """The EDFilter passed as an argument will be run but its filter value will be ignored
0640     """
0641     if isinstance(seq,_SequenceWait):
0642         return _SequenceWaitAndIgnore(seq._operand)
0643     return _SequenceIgnore(seq)
0644 
0645 def wait(seq):
0646     """All modules after this module in the sequence will wait for this module to finish before being scheduled to run.
0647     """
0648     if isinstance(seq,_SequenceIgnore):
0649         return _SequenceWaitAndIgnore(seq._operand)
0650     return _SequenceWait(seq)
0651 
0652 class Path(_ModuleSequenceType):
0653     def __init__(self,*arg,**argv):
0654         super(Path,self).__init__(*arg,**argv)
0655     def _placeImpl(self,name:str,proc):
0656         proc._placePath(name,self)
0657 
0658 class EndPath(_ModuleSequenceType):
0659     def __init__(self,*arg,**argv):
0660         super(EndPath,self).__init__(*arg,**argv)
0661     def _placeImpl(self,name:str,proc):
0662         proc._placeEndPath(name,self)
0663 
0664 class FinalPath(_ModuleSequenceType):
0665     def __init__(self,*arg,**argv):
0666         super(FinalPath,self).__init__(*arg,**argv)
0667     def _placeImpl(self,name:str,proc):
0668         proc._placeFinalPath(name,self)
0669     def associate(self,task):
0670       raise TypeError("FinalPath does not allow associations with Tasks")
0671 
0672 class Sequence(_ModuleSequenceType,_Sequenceable):
0673     def __init__(self,*arg,**argv):
0674         super(Sequence,self).__init__(*arg,**argv)
0675     def _placeImpl(self,name:str,proc):
0676         proc._placeSequence(name,self)
0677     def _clonesequence(self, lookuptable):
0678         if id(self) not in lookuptable:
0679             #for sequences held by sequences we need to clone
0680             # on the first reference
0681             if self._seq is not None:
0682                 clone = type(self)(self._seq._clonesequence(lookuptable))
0683             else:
0684                 clone = type(self)()
0685             lookuptable[id(self)]=clone
0686             lookuptable[id(clone)]=clone
0687         return lookuptable[id(self)]
0688     def _visitSubNodes(self,visitor):
0689         self.visit(visitor)
0690 class SequencePlaceholder(_Sequenceable):
0691     def __init__(self, name:str):
0692         self._name = name
0693     def _placeImpl(self,name:str,proc):
0694         pass
0695     def __str__(self):
0696         return self._name
0697     def insertInto(self, parameterSet, myname:str):
0698         raise RuntimeError("The SequencePlaceholder "+self._name
0699                            +" was never overridden")
0700     def resolve(self, processDict,keepIfCannotResolve:bool=False):
0701         if not self._name in processDict:
0702             #print str(processDict.keys())
0703             if keepIfCannotResolve:
0704                 return self
0705             raise RuntimeError("The SequencePlaceholder "+self._name+ " cannot be resolved.\n Known keys are:"+str(processDict.keys()))
0706         o = processDict[self._name]
0707         if not isinstance(o,_Sequenceable):
0708             raise RuntimeError("The SequencePlaceholder "+self._name+ " refers to an object type which is not allowed to be on a sequence: "+str(type(o)))
0709         return o.resolve(processDict)
0710 
0711     def _clonesequence(self, lookuptable):
0712         if id(self) not in lookuptable:
0713             #for sequences held by sequences we need to clone
0714             # on the first reference
0715             clone = type(self)(self._name)
0716             lookuptable[id(self)]=clone
0717             lookuptable[id(clone)]=clone
0718         return lookuptable[id(self)]
0719     def copy(self):
0720         returnValue =SequencePlaceholder.__new__(type(self))
0721         returnValue.__init__(self._name)
0722         return returnValue
0723     def dumpSequenceConfig(self) -> str:
0724         return 'cms.SequencePlaceholder("%s")' %self._name
0725     def dumpSequencePython(self, options=PrintOptions()) -> str:
0726         return 'cms.SequencePlaceholder("%s")'%self._name
0727     def dumpPython(self, options:PrintOptions=PrintOptions()) -> str:
0728         result = 'cms.SequencePlaceholder(\"'
0729         if options.isCfg:
0730            result += 'process.'
0731         result += self._name+'\")\n'
0732         return result
0733 
0734 
0735 class Schedule(_ValidatingParameterListBase,_ConfigureComponent,_Unlabelable):
0736 
0737     def __init__(self,*arg,**argv):
0738         super(Schedule,self).__init__(*arg)
0739         self._tasks = OrderedSet()
0740         theKeys = list(argv.keys())
0741         if theKeys:
0742             if len(theKeys) > 1 or theKeys[0] != "tasks":
0743                 raise RuntimeError("The Schedule constructor can only have one keyword argument after its Path and\nEndPath arguments and it must use the keyword 'tasks'")
0744             taskList = argv["tasks"]
0745             # Normally we want a list of tasks, but we let it also work if the value is one Task
0746             if isinstance(taskList,Task):
0747                 self.associate(taskList)
0748             else:
0749                 try:
0750                     # Call this just to check that taskList is a list or other iterable object
0751                     self.__dummy(*taskList)
0752                 except:
0753                     raise RuntimeError("The Schedule constructor argument with keyword 'tasks' must have a\nlist (or other iterable object) as its value")
0754                 if taskList:
0755                     self.associate(*taskList)
0756 
0757     def __dummy(self, *args):
0758         pass
0759 
0760     def associate(self,*tasks):
0761         for task in tasks:
0762             if not isinstance(task, Task):
0763                 raise TypeError("The associate function in the class Schedule only works with arguments of type Task")
0764             self._tasks.add(task)
0765     @staticmethod
0766     def _itemIsValid(item) -> bool:
0767         return isinstance(item,Path) or isinstance(item,EndPath) or isinstance(item,FinalPath)
0768     def copy(self):
0769         import copy
0770         aCopy = copy.copy(self)
0771         aCopy._tasks = OrderedSet(self._tasks)
0772         return aCopy
0773     def _place(self,label:str,process):
0774         process.setPartialSchedule_(self,label)
0775     def _replaceIfHeldDirectly(self,original,replacement) -> bool:
0776         """Only replaces an 'original' with 'replacement' if 'original' is directly held.
0777         If a contained Path or Task holds 'original' it will not be replaced."""
0778         didReplace = False
0779         if original in self._tasks:
0780             self._tasks.remove(original)
0781             if replacement is not None:
0782                 self._tasks.add(replacement)
0783             didReplace = True
0784         indices = []
0785         for i, e in enumerate(self):
0786             if original == e:
0787                 indices.append(i)
0788         for i in reversed(indices):
0789             self.pop(i)
0790             if replacement is not None:
0791                 self.insert(i, replacement)
0792             didReplace = True
0793         return didReplace
0794 
0795     def moduleNames(self):
0796         result = set()
0797         visitor = NodeNameVisitor(result)
0798         for seq in self:
0799             seq.visit(visitor)
0800         for t in self._tasks:
0801             t.visit(visitor)
0802         return result
0803     def contains(self, mod) -> bool:
0804         visitor = ContainsModuleVisitor(mod)
0805         for seq in self:
0806             seq.visit(visitor)
0807             if visitor.result():
0808                 return True
0809         for t in self._tasks:
0810             t.visit(visitor)
0811             if visitor.result():
0812                 return True
0813         return visitor.result()
0814     def tasks(self):
0815         """Returns the list of Tasks (that may contain other Tasks) that are associated directly to the Schedule."""
0816         return self._tasks
0817     def dumpPython(self, options:PrintOptions=PrintOptions()) -> str:
0818         pathNames = ['process.'+p.label_() for p in self]
0819         if pathNames:
0820             s=', '.join(pathNames)
0821         else:
0822             s = ''
0823         associationContents = set()
0824         for task in self._tasks:
0825             if task.hasLabel_():
0826                 associationContents.add(_Labelable.dumpSequencePython(task, options))
0827             else:
0828                 associationContents.add(task.dumpPythonNoNewline(options))
0829         taskStrings = list()
0830         for iString in sorted(associationContents):
0831             taskStrings.append(iString)
0832         if taskStrings and s:
0833             return 'cms.Schedule(*[ ' + s + ' ], tasks=[' + ', '.join(taskStrings) + '])\n'
0834         elif s:
0835             return 'cms.Schedule(*[ ' + s + ' ])\n'
0836         elif taskStrings:
0837             return 'cms.Schedule(tasks=[' + ', '.join(taskStrings) + '])\n'
0838         else:
0839             return 'cms.Schedule()\n'
0840 
0841     def __str__(self) -> str:
0842         return self.dumpPython()
0843 
0844 # Fills a list of all Sequences visited
0845 # Can visit a Sequence, Path, or EndPath
0846 class SequenceVisitor(object):
0847     def __init__(self,d):
0848         self.deps = d
0849     def enter(self,visitee):
0850         if isinstance(visitee,Sequence):
0851             self.deps.append(visitee)
0852         pass
0853     def leave(self,visitee):
0854         pass
0855 
0856 # Fills a list of all Tasks visited
0857 # Can visit a Task, Sequence, Path, or EndPath
0858 class TaskVisitor(object):
0859     def __init__(self,d):
0860         self.deps = d
0861     def enter(self,visitee):
0862         if isinstance(visitee,Task):
0863             self.deps.append(visitee)
0864         pass
0865     def leave(self,visitee):
0866         pass
0867 
0868 # Fills a list of all ConditionalTasks visited
0869 # Can visit a ConditionalTask, Sequence, Path, or EndPath
0870 class ConditionalTaskVisitor(object):
0871     def __init__(self,d):
0872         self.deps = d
0873     def enter(self,visitee):
0874         if isinstance(visitee,ConditionalTask):
0875             self.deps.append(visitee)
0876         pass
0877     def leave(self,visitee):
0878         pass
0879 
0880 # Fills a list of all modules visited.
0881 # Can visit a Sequence, Path, EndPath, or Task
0882 # For purposes of this visitor, a module is considered
0883 # to be an object that is one of these types: EDProducer,
0884 # EDFilter, EDAnalyzer, OutputModule, ESProducer, ESSource,
0885 # Service. The last three of these can only appear on a
0886 # Task, they are not sequenceable. An object of one
0887 # of these types is also called a leaf.
0888 class ModuleNodeVisitor(object):
0889     def __init__(self,l):
0890         self.l = l
0891     def enter(self,visitee):
0892         if visitee.isLeaf():
0893             self.l.append(visitee)
0894         pass
0895     def leave(self,visitee):
0896         pass
0897 
0898 # Should not be used on Tasks.
0899 # Similar to ModuleNodeVisitor with the following
0900 # differences. It only lists the modules that were
0901 # contained inside a Task.  It should only be used
0902 # on Sequences, Paths, and EndPaths.
0903 class ModuleNodeOnTaskVisitor(object):
0904     def __init__(self,l):
0905         self.l = l
0906         self._levelInTasks = 0
0907     def enter(self,visitee):
0908         if isinstance(visitee, Task):
0909             self._levelInTasks += 1
0910         if self._levelInTasks == 0:
0911             return
0912         if visitee.isLeaf():
0913             self.l.append(visitee)
0914         pass
0915     def leave(self,visitee):
0916         if self._levelInTasks > 0:
0917             if isinstance(visitee, Task):
0918                 self._levelInTasks -= 1
0919 
0920 class ModuleNodeOnConditionalTaskVisitor(object):
0921     def __init__(self,l):
0922         self.l = l
0923         self._levelInTasks = 0
0924     def enter(self,visitee):
0925         if isinstance(visitee, ConditionalTask):
0926             self._levelInTasks += 1
0927         # This block gets the modules contained by SwitchProducer. It
0928         # needs to be before the "levelInTasks == 0" check because the
0929         # contained modules need to be treated like in ConditionalTask
0930         # also when the SwitchProducer itself is in the Path.
0931         if hasattr(visitee, "modulesForConditionalTask_"):
0932             self.l.extend(visitee.modulesForConditionalTask_())
0933         if self._levelInTasks == 0:
0934             return
0935         if visitee.isLeaf():
0936             self.l.append(visitee)
0937         pass
0938     def leave(self,visitee):
0939         if self._levelInTasks > 0:
0940             if isinstance(visitee, ConditionalTask):
0941                 self._levelInTasks -= 1
0942 
0943 # Should not be used on Tasks.
0944 # Similar to ModuleNodeVisitor with the following
0945 # differences. It only lists the modules that were
0946 # outside a Task, in the sequenced part of the sequence.
0947 # It should only be used on Sequences, Paths, and
0948 # EndPaths.
0949 class ModuleNodeNotOnTaskVisitor(object):
0950     def __init__(self,l):
0951         self.l = l
0952         self._levelInTasks = 0
0953     def enter(self,visitee):
0954         if isinstance(visitee, Task):
0955             self._levelInTasks += 1
0956         if self._levelInTasks > 0:
0957             return
0958         if visitee.isLeaf():
0959             self.l.append(visitee)
0960         pass
0961     def leave(self,visitee):
0962         if self._levelInTasks > 0:
0963             if isinstance(visitee, Task):
0964                 self._levelInTasks -= 1
0965 
0966 # Can visit Tasks, Sequences, Paths, and EndPaths
0967 # result will be set to True if and only if
0968 # the module is in the object directly or
0969 # indirectly through contained Sequences or
0970 # associated Tasks.
0971 class ContainsModuleVisitor(object):
0972     def __init__(self,mod):
0973         self._mod = mod
0974         self._result = False
0975 
0976     def result(self):
0977         return self._result
0978 
0979     def enter(self,visitee):
0980         if self._mod is visitee:
0981             self._result = True
0982 
0983     def leave(self,visitee):
0984         pass
0985 
0986 # Can visit Tasks, Sequences, Paths, and EndPaths
0987 # Fills a set of the names of the visited leaves.
0988 # For the labelable ones the name is the label.
0989 # For a Service the name is the type.
0990 # It raises an exception if a labelable object
0991 # does not have a label at all. It will return
0992 # 'None' if the label attribute exists but was set
0993 # to None. If a Service is not attached to the process
0994 # it will also raise an exception.
0995 class NodeNameVisitor(object):
0996     """ takes a set as input"""
0997     def __init__(self,l):
0998         self.l = l
0999     def enter(self,visitee):
1000         if visitee.isLeaf():
1001             if isinstance(visitee, _Labelable):
1002                 self.l.add(visitee.label_())
1003             else:
1004                 if visitee._inProcess:
1005                     self.l.add(visitee.type_())
1006                 else:
1007                     raise RuntimeError("Service not attached to process: {}".format(visitee.dumpPython()))
1008     def leave(self,visitee):
1009         pass
1010 
1011 # This visitor works only with Sequences, Paths and EndPaths
1012 # It will not work on Tasks
1013 class ExpandVisitor(object):
1014     """ Expands the sequence into leafs and UnaryOperators """
1015     def __init__(self, type):
1016         self._type = type
1017         self.l = []
1018         self.taskLeaves = []
1019         self.taskLeavesInConditionalTasks = []
1020         self.presentTaskLeaves = self.taskLeaves
1021         self._levelInTasks = 0
1022         self.conditionaltaskLeaves = []
1023         self._levelInConditionalTasks = 0
1024 
1025     def enter(self,visitee):
1026         if isinstance(visitee, Task):
1027             self._levelInTasks += 1
1028             return
1029         if isinstance(visitee, ConditionalTask):
1030             self.presentTaskLeaves = self.taskLeavesInConditionalTasks
1031             self._levelInConditionalTasks += 1
1032             return
1033         if visitee.isLeaf():
1034             if self._levelInTasks > 0:
1035                 self.presentTaskLeaves.append(visitee)
1036             elif self._levelInConditionalTasks > 0:
1037                 self.conditionaltaskLeaves.append(visitee)
1038             else:
1039                 self.l.append(visitee)
1040     def leave(self, visitee):
1041         if self._levelInTasks > 0:
1042             if isinstance(visitee, Task):
1043                 self._levelInTasks -= 1
1044             return
1045         if self._levelInConditionalTasks > 0:
1046             if isinstance(visitee, ConditionalTask):
1047                 self._levelInConditionalTasks -= 1
1048                 if 0 == self._levelInConditionalTasks:
1049                   self.presentTaskLeaves = self.taskLeaves
1050             return
1051         if isinstance(visitee,_UnarySequenceOperator):
1052             self.l[-1] = visitee
1053     def result(self):
1054         tsks = []
1055         if self.taskLeaves:
1056           tsks.append(Task(*self.taskLeaves))
1057         if self.conditionaltaskLeaves:
1058           ct = ConditionalTask(*self.conditionaltaskLeaves)
1059           if self.taskLeavesInConditionalTasks:
1060             ct.append(*self.taskLeavesInConditionalTasks)
1061           tsks.append(ct)
1062         if len(self.l) > 0:
1063             # why doesn't (sum(self.l) work?
1064             seq = self.l[0]
1065             for el in self.l[1:]:
1066                 seq += el
1067             return self._type(seq, *tsks)
1068         else:
1069             return self._type(*tsks)
1070     def resultString(self):
1071         sep = ''
1072         returnValue = ''
1073         for m in self.l:
1074             if m is not None:
1075                 returnValue += sep+str(m)
1076                 sep = '+'
1077         if returnValue:
1078             sep = ','
1079         for n in self.taskLeaves:
1080             if n is not None:
1081                 returnValue += sep+str(n)
1082             sep = ','
1083         return returnValue
1084 
1085 
1086 # This visitor is only meant to run on Sequences, Paths, and EndPaths
1087 # It intentionally ignores nodes on Tasks when it does this.
1088 class DecoratedNodeNameVisitor(object):
1089     """ Adds any '!' or '-' needed.  Takes a list """
1090     def __init__(self,l):
1091         self.l = l
1092         self._decoration =''
1093         self._levelInTasks = 0
1094 
1095     def initialize(self):
1096         self.l[:] = []
1097         self._decoration =''
1098         self._levelInTasks = 0
1099 
1100     def enter(self,visitee):
1101         if isinstance(visitee, _TaskBase):
1102             self._levelInTasks += 1
1103         if self._levelInTasks > 0:
1104             return
1105         if visitee.isLeaf():
1106             if hasattr(visitee, "_Labelable__label"):
1107                 self.l.append(self._decoration+visitee.label_())
1108             else:
1109                 error = "An object in a sequence was not found in the process\n"
1110                 if hasattr(visitee, "_filename"):
1111                     error += "From file " + visitee._filename
1112                 else:
1113                     error += "Dump follows\n" + repr(visitee)
1114                 raise RuntimeError(error)
1115         if isinstance(visitee,_BooleanLogicExpression):
1116             self.l.append(self._decoration+visitee.operatorString())
1117         if isinstance(visitee,_UnarySequenceOperator):
1118             self._decoration=visitee.decoration()
1119         else:
1120             self._decoration=''
1121 
1122     def leave(self,visitee):
1123         # Ignore if this visitee is inside a Task
1124         if self._levelInTasks > 0:
1125             if isinstance(visitee, _TaskBase):
1126                 self._levelInTasks -= 1
1127             return
1128         if isinstance(visitee,_BooleanLogicExpression):
1129             #need to add the 'go back' command to keep track of where we are in the tree
1130             self.l.append('@')
1131 
1132 # This visitor is only meant to run on Sequences, Paths, and EndPaths
1133 # Similar to DecoratedNodeNameVistor. The only difference
1134 # is it also builds a separate list of leaves on Tasks.
1135 class DecoratedNodeNamePlusVisitor(object):
1136     """ Adds any '!' or '-' needed.  Takes a list """
1137     def __init__(self,l):
1138         self.l = l
1139         self._decoration =''
1140         self._levelInTasks = 0
1141         self._leavesOnTasks = []
1142 
1143     def initialize(self):
1144         self.l[:] = []
1145         self._decoration =''
1146         self._levelInTasks = 0
1147         self._leavesOnTasks[:] = []
1148 
1149     def enter(self,visitee):
1150         if isinstance(visitee, Task):
1151             self._levelInTasks += 1
1152         if self._levelInTasks > 0:
1153             if visitee.isLeaf():
1154                 self._leavesOnTasks.append(visitee)
1155             return
1156         if visitee.isLeaf():
1157             if hasattr(visitee, "_Labelable__label"):
1158                 self.l.append(self._decoration+visitee.label_())
1159             else:
1160                 error = "An object in a sequence was not found in the process\n"
1161                 if hasattr(visitee, "_filename"):
1162                     error += "From file " + visitee._filename
1163                 else:
1164                     error += "Dump follows\n" + repr(visitee)
1165                 raise RuntimeError(error)
1166         if isinstance(visitee,_BooleanLogicExpression):
1167             self.l.append(self._decoration+visitee.operatorString())
1168         if isinstance(visitee,_UnarySequenceOperator):
1169             self._decoration=visitee.decoration()
1170         else:
1171             self._decoration=''
1172 
1173     def leave(self,visitee):
1174         # Ignore if this visitee is inside a Task
1175         if self._levelInTasks > 0:
1176             if isinstance(visitee, Task):
1177                 self._levelInTasks -= 1
1178             return
1179         if isinstance(visitee,_BooleanLogicExpression):
1180             #need to add the 'go back' command to keep track of where we are in the tree
1181             self.l.append('@')
1182 
1183     def leavesOnTasks(self):
1184         return self._leavesOnTasks
1185 
1186 class _CopyAndExcludeSequenceVisitorOld(object):
1187    """Traverses a Sequence and constructs a new sequence which does not contain modules from the specified list"""
1188    def __init__(self,modulesToRemove):
1189        self.__modulesToIgnore = modulesToRemove
1190        self.__stack = list()
1191        self.__stack.append(list())
1192        self.__result = None
1193        self.__didExclude = False
1194    def enter(self,visitee):
1195        if len(self.__stack) > 0:
1196            #add visitee to its parent's stack entry
1197            self.__stack[-1].append([visitee,False])
1198        if visitee.isLeaf():
1199            if visitee in self.__modulesToIgnore:
1200                self.__didExclude = True
1201                self.__stack[-1][-1]=[None,True]
1202        elif isinstance(visitee, Sequence):
1203            if visitee in self.__modulesToIgnore:
1204                self.__didExclude = True
1205                self.__stack[-1][-1]=[None,True]
1206            self.__stack.append(list())
1207        else:
1208            #need to add a stack entry to keep track of children
1209            self.__stack.append(list())
1210    def leave(self,visitee):
1211        node = visitee
1212        if not visitee.isLeaf():
1213            #were any children changed?
1214            l = self.__stack[-1]
1215            changed = False
1216            countNulls = 0
1217            nonNulls = list()
1218            for c in l:
1219                if c[1] == True:
1220                    changed = True
1221                if c[0] is None:
1222                    countNulls +=1
1223                else:
1224                    nonNulls.append(c[0])
1225            if changed:
1226                self.__didExclude = True
1227                if countNulls != 0:
1228                    #this node must go away
1229                    if len(nonNulls) == 0:
1230                        #all subnodes went away
1231                        node = None
1232                    else:
1233                        node = nonNulls[0]
1234                        for n in nonNulls[1:]:
1235                            node = node+n
1236                else:
1237                    #some child was changed so we need to clone
1238                    # this node and replace it with one that holds
1239                    # the new child(ren)
1240                    children = [x[0] for x in l ]
1241                    if not isinstance(visitee,Sequence):
1242                        node = visitee.__new__(type(visitee))
1243                        node.__init__(*children)
1244                    else:
1245                        node = nonNulls[0]
1246        if node != visitee:
1247            #we had to replace this node so now we need to
1248            # change parent's stack entry as well
1249            if len(self.__stack) > 1:
1250                p = self.__stack[-2]
1251                #find visitee and replace
1252                for i,c in enumerate(p):
1253                    if c[0]==visitee:
1254                        c[0]=node
1255                        c[1]=True
1256                        break
1257        if not visitee.isLeaf():
1258            self.__stack = self.__stack[:-1]
1259    def result(self):
1260        result = None
1261        for n in (x[0] for x in self.__stack[0]):
1262            if n is None:
1263                continue
1264            if result is None:
1265                result = n
1266            else:
1267                result = result+n
1268        return result
1269    def didExclude(self):
1270        return self.__didExclude
1271 
1272 
1273 # This visitor can also be used on Tasks.
1274 class _MutatingSequenceVisitor(object):
1275     """Traverses a Sequence and constructs a new sequence by applying the operator to each element of the sequence"""
1276 
1277     # In many cases this operates in an intuitive manner that needs
1278     # no explanation, but there are some complex cases and I will try to
1279     # explain these in the following comments.
1280     #
1281     # First of all the top level Sequence or Task being visited may contain
1282     # many objects of different types. These contained objects are never
1283     # modified. If they are not left the same, they are instead replaced
1284     # by other instances, replaced by new instances or removed.
1285     # Contained objects are only replaced or removed when they were directly
1286     # modified or if they contain something that was modified.
1287     # If all the contents of a Sequence, Task, _SequenceNegation or _SequenceIgnore
1288     # object that is not at the top level are removed, then the containing
1289     # object is also removed.
1290     # If the contents of a Sequence other than the top level sequence are
1291     # modified, then the sequence elements and Task objects it contains get
1292     # passed up to be included in the top level sequence. If the contents of
1293     # a Task are modified, a new Task object is created and passed up to be
1294     # included in the top level Sequence or Task. If it is a _SequenceNegation
1295     # or _SequenceIgnore instance it will simply be removed completely if its
1296     # operand is removed. If the operand is replaced then a new object of the
1297     # same type will be constructed replacing the old.
1298     #
1299     # Note that if a Sequence contains a SequencePlaceholder, the future contents
1300     # of that placeholder are not affected by the changes. If that is an issue,
1301     # then you probably want to resolve the placeholders before using this
1302     # class.
1303     #
1304     # If this is used multiple times on the same sequence or task, the consequences
1305     # might interfere with one another in unusual cases.
1306     #
1307     # One example, the matching to find objects to modify is based on instances
1308     # (the python id) being the same. So if you modify the contents of a Task or
1309     # Sequence and then subsequently try to modify that Sequence or Task, then
1310     # it will either no longer exist or be a different instance and so nothing
1311     # would get modified.  Note that the one exception to this matching by instance
1312     # is _SequenceIgnore and _SequenceNegation. In that case, two objects are
1313     # recognized as matching if the contained module is the same instance instead
1314     # of requiring the _SequenceNegation or _SequenceIgnore object to be the same
1315     # instance.
1316     #
1317     # Another example. There is an input operator that removes the first instance
1318     # of an object. Applying this visitor with that operation might give unexpected
1319     # results if another operation previously changed the number of times the
1320     # that instance appears or the order it appears in the visitation. This
1321     # should only be an issue if the item is on a Task and even then only in
1322     # unusual circumstances.
1323 
1324     def __init__(self,operator):
1325         self.__operator = operator
1326         # You add a list to the __stack when entering any non-Leaf object
1327         # and pop the last element when leaving any non-Leaf object
1328         self.__stack = list()
1329         self.__stack.append(list())
1330         self.__didApply = False
1331         self.__levelInModifiedNonLeaf = 0
1332     def enter(self,visitee):
1333         # Ignore the content of replaced or removed Sequences,
1334         # Tasks, and operators.
1335         if self.__levelInModifiedNonLeaf > 0:
1336             if not visitee.isLeaf():
1337                 self.__levelInModifiedNonLeaf += 1
1338             return
1339 
1340         # Just a sanity check
1341         if not len(self.__stack) > 0:
1342             raise RuntimeError("LogicError Empty stack in MutatingSequenceVisitor.\n"
1343                                "This should never happen. Contact a Framework developer.")
1344 
1345         # The most important part.
1346         # Apply the operator that might change things, The rest
1347         # of the class is just dealing with side effects of these changes.
1348         v = self.__operator(visitee)
1349 
1350         if v is visitee:
1351             # the operator did not change the visitee
1352             # The 3 element list being appended has the following contents
1353             # element 0 - either the unmodified object, the modified object, or
1354             #   a sequence collection when it is a Sequence whose contents have
1355             #   been modified.
1356             # element 1 - Indicates whether the object was modified.
1357             # element 2 - None or a list of tasks for a Sequence
1358             #   whose contents have been modified.
1359             self.__stack[-1].append([visitee, False, None])
1360             if not visitee.isLeaf():
1361                 # need to add a list to keep track of the contents
1362                 # of the Sequence, Task, or operator we just entered.
1363                 self.__stack.append(list())
1364         else:
1365             # the operator changed the visitee
1366             self.__didApply = True
1367             self.__stack[-1].append([v, True, None])
1368             if not visitee.isLeaf():
1369                 # Set flag to indicate modified Sequence, Task, or operator
1370                 self.__levelInModifiedNonLeaf = 1
1371     def leave(self,visitee):
1372 
1373         # nothing to do for leaf types because they do not have contents
1374         if visitee.isLeaf():
1375             return
1376 
1377         # Ignore if this visitee is inside something that was already removed
1378         # or replaced.
1379         if self.__levelInModifiedNonLeaf > 0:
1380             self.__levelInModifiedNonLeaf -= 1
1381             return
1382 
1383         # Deal with visitees which have contents (Sequence, Task, _SequenceIgnore,
1384         # or _SequenceNegation) and although we know the visitee itself did not get
1385         # changed by the operator, the contents of the visitee might have been changed.
1386 
1387         # did any object inside the visitee change?
1388         contents = self.__stack[-1]
1389         changed = False
1390         allNull = True
1391         for c in contents:
1392             if c[1] == True:
1393                 changed = True
1394             if c[0] is not None:
1395                 allNull = False
1396         if changed:
1397             if allNull:
1398                 self.__stack[-2][-1] = [None, True, None]
1399 
1400             elif isinstance(visitee, _UnarySequenceOperator):
1401                 node = visitee.__new__(type(visitee))
1402                 node.__init__(contents[0][0])
1403                 self.__stack[-2][-1] = [node, True, None]
1404 
1405             elif isinstance(visitee, _TaskBase):
1406                 nonNull = []
1407                 for c in contents:
1408                     if c[0] is not None:
1409                         nonNull.append(c[0])
1410                 self.__stack[-2][-1] = [visitee._makeInstance(*nonNull), True, None]
1411             elif isinstance(visitee, Sequence):
1412                 seq = _SequenceCollection()
1413                 tasks = list()
1414                 for c in contents:
1415                     if c[0] is None:
1416                         continue
1417                     if isinstance(c[0], _TaskBase):
1418                         tasks.append(c[0])
1419                     else:
1420                         seq = seq + c[0]
1421                         if c[2] is not None:
1422                             tasks.extend(c[2])
1423 
1424                 self.__stack[-2][-1] = [seq, True, tasks]
1425 
1426         # When you exit the Sequence, Task, or operator,
1427         # drop the list which holds information about
1428         # its contents.
1429         if not visitee.isLeaf():
1430             self.__stack = self.__stack[:-1]
1431 
1432     def result(self, visitedContainer):
1433 
1434         if isinstance(visitedContainer, _TaskBase):
1435             result = list()
1436             for n in (x[0] for x in self.__stack[0]):
1437                 if n is not None:
1438                     result.append(n)
1439             return result
1440 
1441         seq = _SequenceCollection()
1442         tasks = list()
1443         for c in self.__stack[0]:
1444             if c[0] is None:
1445                 continue
1446             if isinstance(c[0], _TaskBase):
1447                 tasks.append(c[0])
1448             else:
1449                 seq = seq + c[0]
1450                 if c[2] is not None:
1451                     tasks.extend(c[2])
1452         return [seq, tasks]
1453 
1454     def _didApply(self) -> bool:
1455         return self.__didApply
1456 
1457 # This visitor can also be used on Tasks.
1458 class _CopyAndRemoveFirstSequenceVisitor(_MutatingSequenceVisitor):
1459     """Traverses a Sequence and constructs a new sequence which does not contain modules from the specified list"""
1460     def __init__(self,moduleToRemove):
1461         class _RemoveFirstOperator(object):
1462             def __init__(self,moduleToRemove):
1463                 self.__moduleToRemove = moduleToRemove
1464                 self.__found = False
1465             def __call__(self,test):
1466                 if not self.__found and test is self.__moduleToRemove:
1467                     self.__found = True
1468                     return None
1469                 return test
1470         super(type(self),self).__init__(_RemoveFirstOperator(moduleToRemove))
1471     def didRemove(self) -> bool:
1472         return self._didApply()
1473 
1474 # This visitor can also be used on Tasks.
1475 class _CopyAndExcludeSequenceVisitor(_MutatingSequenceVisitor):
1476     """Traverses a Sequence and constructs a new sequence which does not contain the module specified"""
1477     def __init__(self,modulesToRemove):
1478         class _ExcludeOperator(object):
1479             def __init__(self,modulesToRemove):
1480                 self.__modulesToIgnore = modulesToRemove
1481             def __call__(self,test):
1482                 if test in modulesToRemove:
1483                     return None
1484                 return test
1485         super(type(self),self).__init__(_ExcludeOperator(modulesToRemove))
1486     def didExclude(self) -> bool:
1487         return self._didApply()
1488 
1489 # This visitor can also be used on Tasks.
1490 class _CopyAndReplaceSequenceVisitor(_MutatingSequenceVisitor):
1491     """Traverses a Sequence and constructs a new sequence which  replaces a specified module with a different module"""
1492     def __init__(self,target,replace):
1493         class _ReplaceOperator(object):
1494             def __init__(self,target,replace):
1495                 self.__target = target
1496                 self.__replace = replace
1497             def __call__(self,test):
1498                 if test == self.__target:
1499                     return self.__replace
1500                 return test
1501         super(type(self),self).__init__(_ReplaceOperator(target,replace))
1502     def didReplace(self) -> bool:
1503         return self._didApply()
1504 
1505 class _TaskBase(_ConfigureComponent, _Labelable) :
1506     def __init__(self, *items):
1507         self._collection = OrderedSet()
1508         self.add(*items)
1509 
1510     def __setattr__(self,name:str,value):
1511         if not name.startswith("_"):
1512             raise AttributeError("You cannot set parameters for {} objects.".format(self._taskType()))
1513         else:
1514             self.__dict__[name] = value
1515 
1516     def add(self, *items):
1517         for item in items:
1518             if not self._allowedInTask(item):
1519                 raise RuntimeError("Adding an entry of type '{0}' to a {1}.\n"
1520                                    "It is illegal to add this type to a {1}.".format(type(item).__name__, self._taskType()))
1521             self._collection.add(item)
1522 
1523     def fillContents(self, taskContents, options:PrintOptions=PrintOptions()):
1524         # only dump the label, if possible
1525         if self.hasLabel_():
1526             taskContents.add(_Labelable.dumpSequencePython(self, options))
1527         else:
1528             for i in self._collection:
1529                 if isinstance(i, _TaskBase):
1530                     i.fillContents(taskContents, options)
1531                 else:
1532                     taskContents.add(i.dumpSequencePython(options))
1533 
1534     def dumpPython(self, options:PrintOptions=PrintOptions()) -> str:
1535         s = self.dumpPythonNoNewline(options)
1536         return s + "\n"
1537 
1538     def dumpPythonNoNewline(self, options:PrintOptions=PrintOptions()) -> str:
1539         """Returns a string which is the python representation of the object"""
1540         taskContents = set()
1541         for i in self._collection:
1542             if isinstance(i, _TaskBase):
1543                 i.fillContents(taskContents, options)
1544             else:
1545                 taskContents.add(i.dumpSequencePython(options))
1546         s=''
1547         iFirst = True
1548         for item in sorted(taskContents):
1549             if not iFirst:
1550                 s += ", "
1551             iFirst = False
1552             s += item
1553         if len(taskContents) > 255:
1554             s = "*[" + s + "]"
1555         return "cms.{}({})".format(self._taskType(),s)
1556 
1557     def directDependencies(self,sortByType:bool=True):
1558         return findDirectDependencies(self, self._collection,sortByType=sortByType)
1559 
1560     def _isTaskComponent(self) -> bool:
1561         return False
1562 
1563     def isLeaf(self) -> bool:
1564         return False
1565 
1566     def visit(self,visitor):
1567         for i in self._collection:
1568             visitor.enter(i)
1569             if not i.isLeaf():
1570                 i.visit(visitor)
1571             visitor.leave(i)
1572 
1573     def _errorstr(self) -> str:
1574         return "{}(...)".format(self.taskType_())
1575 
1576     def __iter__(self):
1577         for key in self._collection:
1578             yield key
1579 
1580     def __str__(self) -> str:
1581         l = []
1582         v = ModuleNodeVisitor(l)
1583         self.visit(v)
1584         s = ''
1585         for i in l:
1586             if s:
1587                 s += ', '
1588             s += str (i)
1589         return s
1590 
1591     def __repr__(self) -> str:
1592         s = str(self)
1593         return "cms."+type(self).__name__+'('+s+')\n'
1594 
1595     def moduleNames(self):
1596         """Returns a set containing the names of all modules being used"""
1597         result = set()
1598         visitor = NodeNameVisitor(result)
1599         self.visit(visitor)
1600         return result
1601     def contains(self, mod):
1602         visitor = ContainsModuleVisitor(mod)
1603         self.visit(visitor)
1604         return visitor.result()
1605     def copy(self):
1606         return self._makeInstance(*self._collection)
1607     def copyAndExclude(self,listOfModulesToExclude):
1608         """Returns a copy of the sequence which excludes those module in 'listOfModulesToExclude'"""
1609         # You can exclude instances of these types EDProducer, EDFilter, ESSource, ESProducer,
1610         # Service, or Task.
1611         # Mostly this is very intuitive, but there are some complications in cases
1612         # where objects that contain other objects are involved. See the comments
1613         # for the _MutatingSequenceVisitor.
1614         for i in listOfModulesToExclude:
1615             if not i._isTaskComponent():
1616                 raise TypeError("copyAndExclude can only exclude objects that can be placed on a Task")
1617         v = _CopyAndExcludeSequenceVisitor(listOfModulesToExclude)
1618         self.visit(v)
1619         return self._makeInstance(*v.result(self))
1620     def copyAndAdd(self, *modulesToAdd):
1621         """Returns a copy of the Task adding modules/tasks"""
1622         t = self.copy()
1623         t.add(*modulesToAdd)
1624         return t
1625     def expandAndClone(self):
1626         # Name of this function is not very good. It makes a shallow copy with all
1627         # the subTasks flattened out (removed), but keeping all the
1628         # modules that were in those subTasks as well as the top level
1629         # ones.
1630         l = []
1631         v = ModuleNodeVisitor(l)
1632         self.visit(v)
1633         return self._makeInstance(*l)
1634     def replace(self, original, replacement):
1635         """Finds all instances of 'original' and substitutes 'replacement' for them.
1636            Returns 'True' if a replacement occurs."""
1637         # This works for either argument being of type EDProducer, EDFilter, ESProducer,
1638         # ESSource, Service, or Task.
1639         #
1640         # Mostly this is very intuitive, but there are some complications in cases
1641         # where objects that contain other objects are involved. See the comments
1642         # for the _MutatingSequenceVisitor.
1643 
1644         if not self._allowedInTask(original) or (not replacement is None and not self._allowedInTask(replacement)):
1645            raise TypeError("The {0} replace function only works with objects that can be placed on a {0}\n".format(self._taskType()) + \
1646                            "           replace was called with original type = {}\n".format(str(type(original))) + \
1647                            "           and replacement type = {}\n".format(str(type(replacement))))
1648         else:
1649             v = _CopyAndReplaceSequenceVisitor(original,replacement)
1650             self.visit(v)
1651             if v.didReplace():
1652                 self._collection.clear()
1653                 self.add(*v.result(self))
1654             return v.didReplace()
1655 
1656     def remove(self, something):
1657         """Remove the first occurrence of a module
1658            Returns 'True' if the module has been removed, False if it was not found"""
1659         # You can remove instances of these types EDProducer, EDFilter, ESSource,
1660         # ESProducer, Service, or Task,
1661         #
1662         # Mostly this is very intuitive, but there are some complications in cases
1663         # where objects that contain other objects are involved. See the comments
1664         # for the _MutatingSequenceVisitor.
1665         #
1666         # Works very similar to copyAndExclude, there are 2 differences. This changes
1667         # the object itself instead of making a copy and second it only removes
1668         # the first instance of the argument instead of all of them.
1669         if not self._allowedInTask(something):
1670            raise TypeError("remove only works with objects that can be placed on a Task")
1671         v = _CopyAndRemoveFirstSequenceVisitor(something)
1672         self.visit(v)
1673         if v.didRemove():
1674             self._collection.clear()
1675             self.add(*v.result(self))
1676         return v.didRemove()
1677 
1678     def resolve(self, processDict,keepIfCannotResolve:bool=False):
1679         temp = OrderedSet()
1680         for i in self._collection:
1681             if self._mustResolve(i):
1682                 temp.add(i.resolve(processDict,keepIfCannotResolve))
1683             else:
1684                 temp.add(i)
1685         self._collection = temp
1686         return self
1687         
1688 class _TaskBasePlaceholder(object):
1689     def __init__(self, name:str):
1690         self._name = name
1691     def _isTaskComponent(self) -> bool:
1692         return False
1693     def isLeaf(self) -> bool:
1694         return False
1695     def visit(self,visitor):
1696         pass
1697     def __str__(self) -> str:
1698         return self._name
1699     def insertInto(self, parameterSet, myname):
1700         raise RuntimeError("The {} {} was never overridden".format(self._typeName(), self._name))
1701     def resolve(self, processDict,keepIfCannotResolve:bool=False):
1702         if not self._name in processDict:
1703             if keepIfCannotResolve:
1704                 return self
1705             raise RuntimeError("The {} {} cannot be resolved.\n Known keys are: {}".format(self._typeName(), self._name,str(processDict.keys())))
1706         o = processDict[self._name]
1707         if not self._allowedInTask(o):
1708             raise RuntimeError("The {} {} refers to an object type which is not allowed to be on a task: {}".format(self._typeName(), self._name, str(type(o))))
1709         if isinstance(o, self._taskClass()):
1710             return o.resolve(processDict)
1711         return o
1712     def copy(self):
1713         return self._makeInstance(self._name)
1714     def dumpSequencePython(self, options:PrintOptions=PrintOptions()) -> str:
1715         return 'cms.{}("{}")'.format(self._typeName(), self._name)
1716     def dumpPython(self, options:PrintOptions=PrintOptions()) -> str:
1717         result = 'cms.{}(\"'.format(self._typeName())
1718         if options.isCfg:
1719            result += 'process.'
1720         result += self._name+'\")\n'
1721         return result
1722 
1723 class Task(_TaskBase) :
1724     """Holds EDProducers, EDFilters, ESProducers, ESSources, Services, and Tasks.
1725     A Task can be associated with Sequences, Paths, EndPaths, ConditionalTasks and the Schedule.
1726     An EDProducer or EDFilter will be enabled to run unscheduled if it is on
1727     a task associated with the Schedule or any scheduled Path or EndPath (directly
1728     or indirectly through Sequences) and not be on any scheduled Path or EndPath.
1729     ESSources, ESProducers, and Services will be enabled to run if they are on
1730     a Task associated with the Schedule or a scheduled Path or EndPath.  In other
1731     cases, they will be enabled to run if and only if they are not on a Task attached
1732     to the process.
1733     """
1734     @staticmethod
1735     def _taskType() -> str:
1736       return "Task"
1737     def _place(self, name:str, proc):
1738         proc._placeTask(name,self)
1739     def _isTaskComponent(self) -> bool:
1740         return True
1741     @staticmethod
1742     def _makeInstance(*items):
1743       return Task(*items)
1744     @staticmethod
1745     def _allowedInTask(item ) -> bool:
1746       return (isinstance(item, _ConfigureComponent) and item._isTaskComponent()) or isinstance(item, TaskPlaceholder)
1747     @staticmethod
1748     def _mustResolve(item) -> bool:
1749         return isinstance(item, Task) or isinstance(item, TaskPlaceholder)
1750       
1751 class TaskPlaceholder(_TaskBasePlaceholder):
1752     def _isTaskComponent(self) -> bool:
1753         return True
1754     @staticmethod
1755     def _typeName() -> str:
1756       return "TaskPlaceholder"
1757     @staticmethod
1758     def _makeInstance(name):
1759       return TaskPlaceholder(name)
1760     @staticmethod
1761     def _allowedInTask(obj) -> bool:
1762       return Task._allowedInTask(obj)
1763     @staticmethod
1764     def _taskClass():
1765       return Task
1766 
1767 
1768 class ConditionalTask(_TaskBase) :
1769     """Holds EDProducers, EDFilters, ESProducers, ESSources, Services, Tasks and ConditionalTasks.
1770     A ConditionalTask can be associated with Sequences, Paths, and EndPaths.
1771     An EDProducer or EDFilter will be added to a Path or EndPath based on which other
1772     modules on the Path consumes its data products. If that ConditionalTask assigned module
1773     is placed after an EDFilter, the module will only run if the EDFilter passes. If no module
1774     on the Path needs the module's data products, the module will be treated as if it were on a Task.
1775     """
1776     @staticmethod
1777     def _taskType():
1778       return "ConditionalTask"
1779     def _place(self, name:str, proc):
1780         proc._placeConditionalTask(name,self)
1781     def _isTaskComponent(self) -> bool:
1782         return False
1783     @staticmethod
1784     def _makeInstance(*items):
1785       return ConditionalTask(*items)
1786     @staticmethod
1787     def _allowedInTask(item) -> bool:
1788       return isinstance(item, ConditionalTask) or isinstance(item, ConditionalTaskPlaceholder) or Task._allowedInTask(item)
1789     @staticmethod
1790     def _mustResolve(item) -> bool:
1791         return Task._mustResolve(item) or isinstance(item, ConditionalTask) or isinstance(item, ConditionalTaskPlaceholder)
1792 
1793 
1794 class ConditionalTaskPlaceholder(_TaskBasePlaceholder):
1795     def _isTaskComponent(self) -> bool:
1796         return False
1797     @staticmethod
1798     def _typeName() -> str:
1799       return "ConditionalTaskPlaceholder"
1800     @staticmethod
1801     def _makeInstance(name):
1802       return ConditionalTaskPlaceholder(name)
1803     @staticmethod
1804     def _allowedInTask(obj) -> bool:
1805       return Task._allowedInTask(obj) or ConditionalTask._allowedInTask(obj)
1806     @staticmethod
1807     def _taskClass():
1808       return ConditionalTask
1809 
1810 
1811 if __name__=="__main__":
1812     import unittest
1813     class DummyModule(_Labelable, _SequenceLeaf, _ConfigureComponent):
1814         def __init__(self,name):
1815             self.setLabel(name)
1816         def _isTaskComponent(self):
1817             return True
1818         def __repr__(self):
1819             return self.label_()
1820     class DummyBooleanModule(_Labelable, _BooleanLogicSequenceLeaf):
1821         def __init__(self,name):
1822             self.setLabel(name)
1823     class TestModuleCommand(unittest.TestCase):
1824         def setUp(self):
1825             """Nothing to do """
1826             pass
1827         def testBoolean(self):
1828             a = DummyBooleanModule("a")
1829             b = DummyBooleanModule("b")
1830             p = Path( a & b)
1831             self.assertEqual(p.dumpPython(),"cms.Path(process.a&process.b)\n")
1832             l = list()
1833             namesVisitor = DecoratedNodeNameVisitor(l)
1834             p.visit(namesVisitor)
1835             self.assertEqual(l,['&','a','b','@'])
1836             p2 = Path( a | b)
1837             self.assertEqual(p2.dumpPython(),"cms.Path(process.a|process.b)\n")
1838             l[:]=[]
1839             p2.visit(namesVisitor)
1840             self.assertEqual(l,['|','a','b','@'])
1841             c = DummyBooleanModule("c")
1842             d = DummyBooleanModule("d")
1843             p3 = Path(a & b & c & d)
1844             self.assertEqual(p3.dumpPython(),"cms.Path(process.a&process.b&process.c&process.d)\n")
1845             l[:]=[]
1846             p3.visit(namesVisitor)
1847             self.assertEqual(l,['&','a','b','c','d','@'])
1848             p3 = Path(((a & b) & c) & d)
1849             self.assertEqual(p3.dumpPython(),"cms.Path(process.a&process.b&process.c&process.d)\n")
1850             p3 = Path(a & (b & (c & d)))
1851             self.assertEqual(p3.dumpPython(),"cms.Path(process.a&process.b&process.c&process.d)\n")
1852             p3 = Path((a & b) & (c & d))
1853             self.assertEqual(p3.dumpPython(),"cms.Path(process.a&process.b&process.c&process.d)\n")
1854             p3 = Path(a & (b & c) & d)
1855             self.assertEqual(p3.dumpPython(),"cms.Path(process.a&process.b&process.c&process.d)\n")
1856             p4 = Path(a | b | c | d)
1857             self.assertEqual(p4.dumpPython(),"cms.Path(process.a|process.b|process.c|process.d)\n")
1858             p5 = Path(a | b & c & d )
1859             self.assertEqual(p5.dumpPython(),"cms.Path(process.a|(process.b&process.c&process.d))\n")
1860             l[:]=[]
1861             p5.visit(namesVisitor)
1862             self.assertEqual(l,['|','a','&','b','c','d','@','@'])
1863             p5 = Path(a & b | c & d )
1864             self.assertEqual(p5.dumpPython(),"cms.Path((process.a&process.b)|(process.c&process.d))\n")
1865             l[:]=[]
1866             p5.visit(namesVisitor)
1867             self.assertEqual(l,['|','&','a','b','@','&','c','d','@','@'])
1868             p5 = Path(a & (b | c) & d )
1869             self.assertEqual(p5.dumpPython(),"cms.Path(process.a&(process.b|process.c)&process.d)\n")
1870             l[:]=[]
1871             p5.visit(namesVisitor)
1872             self.assertEqual(l,['&','a','|','b','c','@','d','@'])
1873             p5 = Path(a & b & c | d )
1874             self.assertEqual(p5.dumpPython(),"cms.Path((process.a&process.b&process.c)|process.d)\n")
1875             l[:]=[]
1876             p5.visit(namesVisitor)
1877             self.assertEqual(l,['|','&','a','b','c','@','d','@'])
1878             p6 = Path( a & ~b)
1879             self.assertEqual(p6.dumpPython(),"cms.Path(process.a&(~process.b))\n")
1880             l[:]=[]
1881             p6.visit(namesVisitor)
1882             self.assertEqual(l,['&','a','!b','@'])
1883             p6 = Path( a & ignore(b))
1884             self.assertEqual(p6.dumpPython(),"cms.Path(process.a&(cms.ignore(process.b)))\n")
1885             l[:]=[]
1886             p6.visit(namesVisitor)
1887             self.assertEqual(l,['&','a','-b','@'])
1888             p6 = Path( a & wait(b))
1889             self.assertEqual(p6.dumpPython(),"cms.Path(process.a&(cms.wait(process.b)))\n")
1890             l[:]=[]
1891             p6.visit(namesVisitor)
1892             self.assertEqual(l,['&','a','|b','@'])
1893             p6 = Path( a & wait(ignore(b)))
1894             self.assertEqual(p6.dumpPython(),"cms.Path(process.a&(cms.wait(cms.ignore(process.b))))\n")
1895             l[:]=[]
1896             p6.visit(namesVisitor)
1897             self.assertEqual(l,['&','a','+b','@'])
1898             p6 = Path( a & ignore(wait(b)))
1899             self.assertEqual(p6.dumpPython(),"cms.Path(process.a&(cms.wait(cms.ignore(process.b))))\n")
1900             l[:]=[]
1901             p6.visit(namesVisitor)
1902             self.assertEqual(l,['&','a','+b','@'])
1903             p6 = Path(~(a&b))
1904             self.assertEqual(p6.dumpPython(),"cms.Path(~(process.a&process.b))\n")
1905             l[:]=[]
1906             p6.visit(namesVisitor)
1907             self.assertEqual(l,['!&','a','b','@'])
1908 
1909         def testTaskConstructor(self):
1910             a = DummyModule("a")
1911             self.assertRaises(RuntimeError, lambda : Task(ConditionalTask(a)) )
1912 
1913         def testDumpPython(self):
1914             a = DummyModule("a")
1915             b = DummyModule('b')
1916             p = Path((a*b))
1917             #print p.dumpConfig('')
1918             self.assertEqual(p.dumpPython(),"cms.Path(process.a+process.b)\n")
1919             p2 = Path((b+a))
1920             #print p2.dumpConfig('')
1921             self.assertEqual(p2.dumpPython(),"cms.Path(process.b+process.a)\n")
1922             c = DummyModule('c')
1923             p3 = Path(c*(a+b))
1924             #print p3.dumpConfig('')
1925             self.assertEqual(p3.dumpPython(),"cms.Path(process.c+process.a+process.b)\n")
1926             p4 = Path(c*a+b)
1927             #print p4.dumpConfig('')
1928             self.assertEqual(p4.dumpPython(),"cms.Path(process.c+process.a+process.b)\n")
1929             p5 = Path(a+ignore(b))
1930             #print p5.dumpConfig('')
1931             self.assertEqual(p5.dumpPython(),"cms.Path(process.a+cms.ignore(process.b))\n")
1932             p5a = Path(a+wait(b))
1933             self.assertEqual(p5a.dumpPython(),"cms.Path(process.a+cms.wait(process.b))\n")
1934             p5b = Path(a+ignore(wait(b)))
1935             self.assertEqual(p5b.dumpPython(),"cms.Path(process.a+cms.wait(cms.ignore(process.b)))\n")
1936             p5c = Path(a+wait(ignore(b)))
1937             self.assertEqual(p5c.dumpPython(),"cms.Path(process.a+cms.wait(cms.ignore(process.b)))\n")
1938             p6 = Path(c+a*b)
1939             #print p6.dumpConfig('')
1940             self.assertEqual(p6.dumpPython(),"cms.Path(process.c+process.a+process.b)\n")
1941             p7 = Path(a+~b)
1942             self.assertEqual(p7.dumpPython(),"cms.Path(process.a+~process.b)\n")
1943             p8 = Path((a+b)*c)
1944             self.assertEqual(p8.dumpPython(),"cms.Path(process.a+process.b+process.c)\n")
1945             t1 = Task(a)
1946             t2 = Task(c, b)
1947             t3 = Task()
1948             p9 = Path((a+b)*c, t1)
1949             self.assertEqual(p9.dumpPython(),"cms.Path(process.a+process.b+process.c, cms.Task(process.a))\n")
1950             p10 = Path((a+b)*c, t2, t1)
1951             self.assertEqual(p10.dumpPython(),"cms.Path(process.a+process.b+process.c, cms.Task(process.a), cms.Task(process.b, process.c))\n")
1952             p11 = Path(t1, t2, t3)
1953             self.assertEqual(p11.dumpPython(),"cms.Path(cms.Task(), cms.Task(process.a), cms.Task(process.b, process.c))\n")
1954             d = DummyModule("d")
1955             e = DummyModule('e')
1956             f = DummyModule('f')
1957             t4 = Task(d, Task(f))
1958             s = Sequence(e, t4)
1959             p12 = Path(a+b+s+c,t1)
1960             self.assertEqual(p12.dumpPython(),"cms.Path(process.a+process.b+cms.Sequence(process.e, cms.Task(process.d, process.f))+process.c, cms.Task(process.a))\n")
1961             ct1 = ConditionalTask(a)
1962             ct2 = ConditionalTask(c, b)
1963             ct3 = ConditionalTask()
1964             p13 = Path((a+b)*c, ct1)
1965             self.assertEqual(p13.dumpPython(),"cms.Path(process.a+process.b+process.c, cms.ConditionalTask(process.a))\n")
1966             p14 = Path((a+b)*c, ct2, ct1)
1967             self.assertEqual(p14.dumpPython(),"cms.Path(process.a+process.b+process.c, cms.ConditionalTask(process.a), cms.ConditionalTask(process.b, process.c))\n")
1968             p15 = Path(ct1, ct2, ct3)
1969             self.assertEqual(p15.dumpPython(),"cms.Path(cms.ConditionalTask(), cms.ConditionalTask(process.a), cms.ConditionalTask(process.b, process.c))\n")
1970             ct4 = ConditionalTask(d, Task(f))
1971             s = Sequence(e, ct4)
1972             p16 = Path(a+b+s+c,ct1)
1973             self.assertEqual(p16.dumpPython(),"cms.Path(process.a+process.b+cms.Sequence(process.e, cms.ConditionalTask(process.d, process.f))+process.c, cms.ConditionalTask(process.a))\n")
1974 
1975             n = 260
1976             mods = []
1977             labels = []
1978             for i in range(0, n):
1979                 l = "a{}".format(i)
1980                 labels.append("process."+l)
1981                 mods.append(DummyModule(l))
1982             labels.sort()
1983             task = Task(*mods)
1984             self.assertEqual(task.dumpPython(), "cms.Task(*[" + ", ".join(labels) + "])\n")
1985             conditionalTask = ConditionalTask(*mods)
1986             self.assertEqual(conditionalTask.dumpPython(), "cms.ConditionalTask(*[" + ", ".join(labels) + "])\n")
1987 
1988             l = list()
1989             namesVisitor = DecoratedNodeNameVisitor(l)
1990             p.visit(namesVisitor)
1991             self.assertEqual(l, ['a', 'b'])
1992             l[:] = []
1993             p5.visit(namesVisitor)
1994             self.assertEqual(l, ['a', '-b'])
1995             l[:] = []
1996             p5a.visit(namesVisitor)
1997             self.assertEqual(l, ['a', '|b'])
1998             l[:] = []
1999             p5b.visit(namesVisitor)
2000             self.assertEqual(l, ['a', '+b'])
2001             l[:] = []
2002             p5c.visit(namesVisitor)
2003             self.assertEqual(l, ['a', '+b'])
2004             l[:] = []
2005             p7.visit(namesVisitor)
2006             self.assertEqual(l, ['a', '!b'])
2007             l[:] = []
2008             p10.visit(namesVisitor)
2009             self.assertEqual(l, ['a', 'b', 'c'])
2010             l[:] = []
2011             p12.visit(namesVisitor)
2012             self.assertEqual(l, ['a', 'b', 'e', 'c'])
2013             l[:] = []
2014             p16.visit(namesVisitor)
2015             self.assertEqual(l, ['a', 'b', 'e', 'c'])
2016             l[:] = []
2017             moduleVisitor = ModuleNodeVisitor(l)
2018             p8.visit(moduleVisitor)
2019             names = [m.label_() for m in l]
2020             self.assertEqual(names, ['a', 'b', 'c'])
2021             tph = TaskPlaceholder('a')
2022             self.assertEqual(tph.dumpPython(), 'cms.TaskPlaceholder("process.a")\n')
2023             sph = SequencePlaceholder('a')
2024             self.assertEqual(sph.dumpPython(), 'cms.SequencePlaceholder("process.a")\n')
2025             ctph = ConditionalTaskPlaceholder('a')
2026             self.assertEqual(ctph.dumpPython(), 'cms.ConditionalTaskPlaceholder("process.a")\n')
2027 
2028         def testDumpConfig(self):
2029             a = DummyModule("a")
2030             b = DummyModule('b')
2031             p = Path((a*b))
2032             #print p.dumpConfig('')
2033             self.assertEqual(p.dumpConfig(None),"{a&b}\n")
2034             p2 = Path((b+a))
2035             #print p2.dumpConfig('')
2036             self.assertEqual(p2.dumpConfig(None),"{b&a}\n")
2037             c = DummyModule('c')
2038             p3 = Path(c*(a+b))
2039             #print p3.dumpConfig('')
2040             self.assertEqual(p3.dumpConfig(None),"{c&a&b}\n")
2041             p4 = Path(c*a+b)
2042             #print p4.dumpConfig('')
2043             self.assertEqual(p4.dumpConfig(None),"{c&a&b}\n")
2044             p5 = Path(a+ignore(b))
2045             #print p5.dumpConfig('')
2046             self.assertEqual(p5.dumpConfig(None),"{a&-b}\n")
2047             p6 = Path(c+a*b)
2048             #print p6.dumpConfig('')
2049             self.assertEqual(p6.dumpConfig(None),"{c&a&b}\n")
2050             p7 = Path(a+~b)
2051             self.assertEqual(p7.dumpConfig(None),"{a&!b}\n")
2052             p8 = Path((a+b)*c)
2053             self.assertEqual(p8.dumpConfig(None),"{a&b&c}\n")
2054         def testVisitor(self):
2055             class TestVisitor(object):
2056                 def __init__(self, enters, leaves):
2057                     self._enters = enters
2058                     self._leaves = leaves
2059                 def enter(self,visitee):
2060                     #print visitee.dumpSequencePython()
2061                     if self._enters[0] != visitee:
2062                         raise RuntimeError("wrong node ("+str(visitee)+") on 'enter'")
2063                     else:
2064                         self._enters = self._enters[1:]
2065                 def leave(self,visitee):
2066                     if self._leaves[0] != visitee:
2067                         raise RuntimeError("wrong node ("+str(visitee)+") on 'leave'\n expected ("+str(self._leaves[0])+")")
2068                     else:
2069                         self._leaves = self._leaves[1:]
2070             a = DummyModule("a")
2071             b = DummyModule('b')
2072             multAB = a*b
2073             p = Path(multAB)
2074             t = TestVisitor(enters=[a,b],
2075                             leaves=[a,b])
2076             p.visit(t)
2077 
2078             plusAB = a+b
2079             p = Path(plusAB)
2080             t = TestVisitor(enters=[a,b],
2081                             leaves=[a,b])
2082             p.visit(t)
2083 
2084             c=DummyModule("c")
2085             d=DummyModule("d")
2086             e=DummyModule("e")
2087             f=DummyModule("f")
2088             g=DummyModule("g")
2089             ct1 = ConditionalTask(d)
2090             ct2 = ConditionalTask(e, ct1)
2091             ct3 = ConditionalTask(f, g, ct2)
2092             s=Sequence(plusAB, ct3, ct2)
2093             multSC = s*c
2094             p=Path(multSC, ct1, ct2)
2095             l = []
2096             v = ModuleNodeVisitor(l)
2097             p.visit(v)
2098             expected = [a,b,f,g,e,d,e,d,c,d,e,d]
2099             self.assertEqual(expected,l)
2100 
2101 
2102             t1 = Task(d)
2103             t2 = Task(e, t1)
2104             t3 = Task(f, g, t2)
2105             s=Sequence(plusAB, t3, t2)
2106             multSC = s*c
2107             p=Path(multSC, t1, t2)
2108 
2109             l = []
2110             v = ModuleNodeVisitor(l)
2111             p.visit(v)
2112             expected = [a,b,f,g,e,d,e,d,c,d,e,d]
2113             self.assertEqual(expected,l)
2114 
2115             l[:] = []
2116             v = ModuleNodeOnTaskVisitor(l)
2117             p.visit(v)
2118             expected = [f,g,e,d,e,d,d,e,d]
2119             self.assertEqual(expected,l)
2120 
2121             l[:] = []
2122             v = ModuleNodeNotOnTaskVisitor(l)
2123             p.visit(v)
2124             expected = [a,b,c]
2125             self.assertEqual(expected,l)
2126 
2127 
2128             t=TestVisitor(enters=[s,a,b,t3,f,g,t2,e,t1,d,t2,e,t1,d,c,t1,d,t2,e,t1,d],
2129                           leaves=[a,b,f,g,e,d,t1,t2,t3,e,d,t1,t2,s,c,d,t1,e,d,t1,t2])
2130             p.visit(t)
2131 
2132             notA= ~a
2133             p=Path(notA)
2134             t=TestVisitor(enters=[notA,a],leaves=[a,notA])
2135             p.visit(t)
2136         def testResolve(self):
2137             m1 = DummyModule("m1")
2138             m2 = DummyModule("m2")
2139             s1 = Sequence(m1)
2140             s2 = SequencePlaceholder("s3")
2141             s3 = Sequence(m2)
2142             p = Path(s1*s2)
2143             l = list()
2144             #resolver = ResolveVisitor(d)
2145             #p.visit(resolver)
2146             namesVisitor = DecoratedNodeNameVisitor(l)
2147             p.visit(namesVisitor)
2148             self.assertEqual(l, ['m1'])
2149             p.resolve(dict(s1=s1, s2=s2, s3=s3))
2150             l[:] = []
2151             p.visit(namesVisitor)
2152             self.assertEqual(l, ['m1', 'm2'])
2153             l[:]=[]
2154             s1 = Sequence(m1)
2155             s2 = SequencePlaceholder("s3")
2156             s3 = Sequence(m2)
2157             s4 = SequencePlaceholder("s2")
2158             p=Path(s1+s4)
2159             p.resolve(dict(s1=s1, s2=s2, s3=s3, s4=s4))
2160             p.visit(namesVisitor)
2161             self.assertEqual(l, ['m1', 'm2'])
2162             l[:]=[]
2163             m3 = DummyModule("m3")
2164             m4 = DummyModule("m4")
2165             s1 = Sequence(~m1)
2166             s2 = SequencePlaceholder("s3")
2167             s3 = Sequence(ignore(m2))
2168             s4 = Sequence(wait(m3) + ignore(wait(m4)))
2169             d = dict(s1=s1, s2=s2, s3=s3, s4=s4)
2170             p = Path(s1*s2*s4)
2171             p.resolve(dict(s1=s1, s2=s2, s3=s3, s4=s4))
2172             p.visit(namesVisitor)
2173             self.assertEqual(l, ['!m1', '-m2', '|m3', '+m4'])
2174         def testReplace(self):
2175             m1 = DummyModule("m1")
2176             m2 = DummyModule("m2")
2177             m3 = DummyModule("m3")
2178             m4 = DummyModule("m4")
2179             m5 = DummyModule("m5")
2180 
2181             s1 = Sequence(m1*~m2*m1*m2*ignore(m2))
2182             s2 = Sequence(m1*m2)
2183             l = []
2184             namesVisitor = DecoratedNodeNameVisitor(l)
2185             s1.visit(namesVisitor)
2186             self.assertEqual(l,['m1', '!m2', 'm1', 'm2', '-m2'])
2187 
2188             s3 = Sequence(~m1*s2)
2189             s3.replace(~m1, m2)
2190             l[:] = []
2191             s3.visit(namesVisitor)
2192             self.assertEqual(l, ['m2', 'm1', 'm2'])
2193             s3.replace(m2, ~m1)
2194             l[:] = []
2195             s3.visit(namesVisitor)
2196             self.assertEqual(l, ['!m1', 'm1', '!m1'])
2197 
2198             s3 = Sequence(ignore(m1)*s2)
2199             s3.replace(ignore(m1), m2)
2200             l[:] = []
2201             s3.visit(namesVisitor)
2202             self.assertEqual(l, ['m2', 'm1', 'm2'])
2203             s3.replace(m2, ignore(m1))
2204             l[:] = []
2205             s3.visit(namesVisitor)
2206             self.assertEqual(l, ['-m1', 'm1', '-m1'])
2207 
2208             ph = SequencePlaceholder('x')
2209             s4 = Sequence(Sequence(ph))
2210             s4.replace(ph,m2)
2211             self.assertEqual(s4.dumpPython(), "cms.Sequence(process.m2)\n")
2212 
2213             s1.replace(m2,m3)
2214             l[:] = []
2215             s1.visit(namesVisitor)
2216             self.assertEqual(l,['m1', '!m3', 'm1', 'm3', '-m3'])
2217             s2 = Sequence(m1*m2)
2218             s3 = Sequence(~m1*s2)
2219             l[:] = []
2220             s3.visit(namesVisitor)
2221             self.assertEqual(l,['!m1', 'm1', 'm2'])
2222             l[:] = []
2223             s3.replace(s2,m1)
2224             s3.visit(namesVisitor)
2225             self.assertEqual(l,['!m1', 'm1'])
2226 
2227             s1 = Sequence(m1+m2)
2228             s2 = Sequence(m3+m4)
2229             s3 = Sequence(s1+s2)
2230             s3.replace(m3,m5)
2231             l[:] = []
2232             s3.visit(namesVisitor)
2233             self.assertEqual(l,['m1','m2','m5','m4'])
2234 
2235             m6 = DummyModule("m6")
2236             m7 = DummyModule("m7")
2237             m8 = DummyModule("m8")
2238             m9 = DummyModule("m9")
2239 
2240             #Task
2241             t6 = Task(m6)
2242             t7 = Task(m7)
2243             t89 = Task(m8, m9)
2244 
2245             s1 = Sequence(m1+m2, t6)
2246             s2 = Sequence(m3+m4, t7)
2247             s3 = Sequence(s1+s2, t89)
2248             s3.replace(m3,m5)
2249             l[:] = []
2250             s3.visit(namesVisitor)
2251             self.assertEqual(l,['m1','m2','m5','m4'])
2252 
2253             s3.replace(m8,m1)
2254             self.assertTrue(s3.dumpPython() == "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.Task(process.m6))+process.m5+process.m4, cms.Task(process.m1, process.m9), cms.Task(process.m7))\n")
2255 
2256             s3.replace(m1,m7)
2257             self.assertTrue(s3.dumpPython() == "cms.Sequence(process.m7+process.m2+process.m5+process.m4, cms.Task(process.m6), cms.Task(process.m7), cms.Task(process.m7, process.m9))\n")
2258             result = s3.replace(t7, t89)
2259             self.assertTrue(s3.dumpPython() == "cms.Sequence(process.m7+process.m2+process.m5+process.m4, cms.Task(process.m6), cms.Task(process.m7, process.m9), cms.Task(process.m8, process.m9))\n")
2260             self.assertTrue(result)
2261             result = s3.replace(t7, t89)
2262             self.assertFalse(result)
2263 
2264             t1 = Task()
2265             t1.replace(m1,m2)
2266             self.assertTrue(t1.dumpPython() == "cms.Task()\n")
2267 
2268             t1 = Task(m1)
2269             t1.replace(m1,m2)
2270             self.assertTrue(t1.dumpPython() == "cms.Task(process.m2)\n")
2271 
2272             t1 = Task(m1,m2, m2)
2273             t1.replace(m2,m3)
2274             self.assertTrue(t1.dumpPython() == "cms.Task(process.m1, process.m3)\n")
2275 
2276             t1 = Task(m1,m2)
2277             t2 = Task(m1,m3,t1)
2278             t2.replace(m1,m4)
2279             self.assertTrue(t2.dumpPython() == "cms.Task(process.m2, process.m3, process.m4)\n")
2280 
2281             t1 = Task(m2)
2282             t2 = Task(m1,m3,t1)
2283             t2.replace(m1,m4)
2284             self.assertTrue(t2.dumpPython() == "cms.Task(process.m2, process.m3, process.m4)\n")
2285 
2286             t1 = Task(m2)
2287             t2 = Task(m1,m3,t1)
2288             t2.replace(t1,m4)
2289             self.assertTrue(t2.dumpPython() == "cms.Task(process.m1, process.m3, process.m4)\n")
2290 
2291             t1 = Task(m2)
2292             t2 = Task(m1,m3,t1)
2293             t3 = Task(m5)
2294             t2.replace(m2,t3)
2295             self.assertTrue(t2.dumpPython() == "cms.Task(process.m1, process.m3, process.m5)\n")
2296 
2297             #ConditionalTask
2298             ct6 = ConditionalTask(m6)
2299             ct7 = ConditionalTask(m7)
2300             ct89 = ConditionalTask(m8, m9)
2301 
2302             cs1 = Sequence(m1+m2, ct6)
2303             cs2 = Sequence(m3+m4, ct7)
2304             cs3 = Sequence(cs1+cs2, ct89)
2305             cs3.replace(m3,m5)
2306             l[:] = []
2307             cs3.visit(namesVisitor)
2308             self.assertEqual(l,['m1','m2','m5','m4'])
2309 
2310             cs3.replace(m8,m1)
2311             self.assertEqual(cs3.dumpPython(), "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.ConditionalTask(process.m6))+process.m5+process.m4, cms.ConditionalTask(process.m1, process.m9), cms.ConditionalTask(process.m7))\n")
2312 
2313             cs3.replace(m1,m7)
2314             self.assertEqual(cs3.dumpPython(), "cms.Sequence(process.m7+process.m2+process.m5+process.m4, cms.ConditionalTask(process.m6), cms.ConditionalTask(process.m7), cms.ConditionalTask(process.m7, process.m9))\n")
2315             result = cs3.replace(ct7, ct89)
2316             self.assertEqual(cs3.dumpPython(), "cms.Sequence(process.m7+process.m2+process.m5+process.m4, cms.ConditionalTask(process.m6), cms.ConditionalTask(process.m7, process.m9), cms.ConditionalTask(process.m8, process.m9))\n")
2317             self.assertTrue(result)
2318             result = cs3.replace(ct7, ct89)
2319             self.assertFalse(result)
2320 
2321             ct1 = ConditionalTask()
2322             ct1.replace(m1,m2)
2323             self.assertEqual(ct1.dumpPython(), "cms.ConditionalTask()\n")
2324 
2325             ct1 = ConditionalTask(m1)
2326             ct1.replace(m1,m2)
2327             self.assertEqual(ct1.dumpPython(), "cms.ConditionalTask(process.m2)\n")
2328 
2329             ct1 = ConditionalTask(m1,m2, m2)
2330             ct1.replace(m2,m3)
2331             self.assertEqual(ct1.dumpPython(), "cms.ConditionalTask(process.m1, process.m3)\n")
2332 
2333             ct1 = ConditionalTask(m1,m2)
2334             ct2 = ConditionalTask(m1,m3,ct1)
2335             ct2.replace(m1,m4)
2336             self.assertEqual(ct2.dumpPython(), "cms.ConditionalTask(process.m2, process.m3, process.m4)\n")
2337 
2338             ct1 = ConditionalTask(m2)
2339             ct2 = ConditionalTask(m1,m3,ct1)
2340             ct2.replace(m1,m4)
2341             self.assertEqual(ct2.dumpPython(), "cms.ConditionalTask(process.m2, process.m3, process.m4)\n")
2342 
2343             ct1 = ConditionalTask(m2)
2344             ct2 = ConditionalTask(m1,m3,ct1)
2345             ct2.replace(ct1,m4)
2346             self.assertEqual(ct2.dumpPython(), "cms.ConditionalTask(process.m1, process.m3, process.m4)\n")
2347 
2348             ct1 = ConditionalTask(m2)
2349             ct2 = ConditionalTask(m1,m3,ct1)
2350             ct3 = ConditionalTask(m5)
2351             ct2.replace(m2,ct3)
2352             self.assertEqual(ct2.dumpPython(), "cms.ConditionalTask(process.m1, process.m3, process.m5)\n")
2353 
2354             #FinalPath
2355             fp = FinalPath()
2356             fp.replace(m1,m2)
2357             self.assertEqual(fp.dumpPython(), "cms.FinalPath()\n")
2358             fp = FinalPath(m1)
2359             fp.replace(m1,m2)
2360             self.assertEqual(fp.dumpPython(), "cms.FinalPath(process.m2)\n")
2361 
2362         def testReplaceIfHeldDirectly(self):
2363             m1 = DummyModule("m1")
2364             m2 = DummyModule("m2")
2365             m3 = DummyModule("m3")
2366             m4 = DummyModule("m4")
2367             m5 = DummyModule("m5")
2368 
2369             s1 = Sequence(m1*~m2*m1*m2*ignore(m2))
2370             s1._replaceIfHeldDirectly(m2,m3)
2371             self.assertEqual(s1.dumpPython()[:-1],
2372                              "cms.Sequence(process.m1+~process.m3+process.m1+process.m3+cms.ignore(process.m3))")
2373 
2374             s2 = Sequence(m1*m2)
2375             l = []
2376             s3 = Sequence(~m1*s2)
2377             s3._replaceIfHeldDirectly(~m1, m2)
2378             self.assertEqual(s3.dumpPython()[:-1],
2379                              "cms.Sequence(process.m2+(process.m1+process.m2))")
2380             #Task
2381             m6 = DummyModule("m6")
2382             m7 = DummyModule("m7")
2383             m8 = DummyModule("m8")
2384             m9 = DummyModule("m9")
2385             t6 = Task(m6)
2386             t7 = Task(m7)
2387             t89 = Task(m8, m9)
2388 
2389             s1 = Sequence(m1+m2, t6)
2390             s2 = Sequence(m3+m4, t7)
2391             s3 = Sequence(s1+s2, t89)
2392             s3._replaceIfHeldDirectly(m3,m5)
2393             self.assertEqual(s3.dumpPython()[:-1], "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.Task(process.m6))+cms.Sequence(process.m3+process.m4, cms.Task(process.m7)), cms.Task(process.m8, process.m9))")
2394             s2._replaceIfHeldDirectly(m3,m5)
2395             self.assertEqual(s2.dumpPython()[:-1],"cms.Sequence(process.m5+process.m4, cms.Task(process.m7))")
2396             self.assertEqual(s3.dumpPython()[:-1], "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.Task(process.m6))+cms.Sequence(process.m5+process.m4, cms.Task(process.m7)), cms.Task(process.m8, process.m9))")
2397 
2398             s1 = Sequence(t6)
2399             s1._replaceIfHeldDirectly(t6,t7)
2400             self.assertEqual(s1.dumpPython()[:-1],"cms.Sequence(cms.Task(process.m7))")
2401 
2402             #ConditionalTask
2403             ct6 = ConditionalTask(m6)
2404             ct7 = ConditionalTask(m7)
2405             ct89 = ConditionalTask(m8, m9)
2406 
2407             s1 = Sequence(m1+m2, ct6)
2408             s2 = Sequence(m3+m4, ct7)
2409             s3 = Sequence(s1+s2, ct89)
2410             s3._replaceIfHeldDirectly(m3,m5)
2411             self.assertEqual(s3.dumpPython()[:-1], "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.ConditionalTask(process.m6))+cms.Sequence(process.m3+process.m4, cms.ConditionalTask(process.m7)), cms.ConditionalTask(process.m8, process.m9))")
2412             s2._replaceIfHeldDirectly(m3,m5)
2413             self.assertEqual(s2.dumpPython()[:-1],"cms.Sequence(process.m5+process.m4, cms.ConditionalTask(process.m7))")
2414             self.assertEqual(s3.dumpPython()[:-1], "cms.Sequence(cms.Sequence(process.m1+process.m2, cms.ConditionalTask(process.m6))+cms.Sequence(process.m5+process.m4, cms.ConditionalTask(process.m7)), cms.ConditionalTask(process.m8, process.m9))")
2415 
2416             s1 = Sequence(ct6)
2417             s1._replaceIfHeldDirectly(ct6,ct7)
2418             self.assertEqual(s1.dumpPython()[:-1],"cms.Sequence(cms.ConditionalTask(process.m7))")
2419         def testIndex(self):
2420             m1 = DummyModule("a")
2421             m2 = DummyModule("b")
2422             m3 = DummyModule("c")
2423 
2424             s = Sequence(m1+m2+m3)
2425             self.assertEqual(s.index(m1),0)
2426             self.assertEqual(s.index(m2),1)
2427             self.assertEqual(s.index(m3),2)
2428 
2429         def testInsert(self):
2430             m1 = DummyModule("a")
2431             m2 = DummyModule("b")
2432             m3 = DummyModule("c")
2433             s = Sequence(m1+m3)
2434             s.insert(1,m2)
2435             self.assertEqual(s.index(m1),0)
2436             self.assertEqual(s.index(m2),1)
2437             self.assertEqual(s.index(m3),2)
2438 
2439             s = Sequence()
2440             s.insert(0, m1)
2441             self.assertEqual(s.index(m1),0)
2442 
2443             p = Path()
2444             p.insert(0, m1)
2445             self.assertEqual(s.index(m1),0)
2446 
2447         def testExpandAndClone(self):
2448             m1 = DummyModule("m1")
2449             m2 = DummyModule("m2")
2450             m3 = DummyModule("m3")
2451             m4 = DummyModule("m4")
2452             m5 = DummyModule("m5")
2453 
2454             s1 = Sequence(m1*~m2*m1*m2*ignore(m2))
2455             s2 = Sequence(m1*m2)
2456             s3 = Sequence(~m1*s2)
2457 
2458             p = Path(s1+s3)
2459             p2 = p.expandAndClone()
2460             l = []
2461             namesVisitor = DecoratedNodeNameVisitor(l)
2462             p2.visit(namesVisitor)
2463             self.assertEqual(l, ['m1', '!m2', 'm1', 'm2', '-m2', '!m1', 'm1', 'm2'])
2464 
2465             #Task
2466             m6 = DummyModule("m6")
2467             m7 = DummyModule("m7")
2468             m8 = DummyModule("m8")
2469             m9 = DummyModule("m9")
2470             p = Path(s1+s3, Task(m6))
2471             p2 = p.expandAndClone()
2472             l[:] = []
2473             p2.visit(namesVisitor)
2474             self.assertEqual(l, ['m1', '!m2', 'm1', 'm2', '-m2', '!m1', 'm1', 'm2'])
2475             self.assertEqual(p2.dumpPython(), "cms.Path(process.m1+~process.m2+process.m1+process.m2+cms.ignore(process.m2)+~process.m1+process.m1+process.m2, cms.Task(process.m6))\n")
2476 
2477             s2 = Sequence(m1*m2, Task(m9))
2478             s3 = Sequence(~m1*s2)
2479             t8 = Task(m8)
2480             t8.setLabel("t8")
2481             p = Path(s1+s3, Task(m6, Task(m7, t8)))
2482             p2 = p.expandAndClone()
2483             l[:] = []
2484             p2.visit(namesVisitor)
2485             self.assertEqual(l, ['m1', '!m2', 'm1', 'm2', '-m2', '!m1', 'm1', 'm2'])
2486             self.assertTrue(p2.dumpPython() == "cms.Path(process.m1+~process.m2+process.m1+process.m2+cms.ignore(process.m2)+~process.m1+process.m1+process.m2, cms.Task(process.m6, process.m7, process.m8, process.m9))\n")
2487 
2488             t1 = Task(m1,m2,m3)
2489             s1 = Sequence(t1)
2490             s2 = s1.expandAndClone()
2491             l[:] = []
2492             s2.visit(namesVisitor)
2493             self.assertEqual(l, [])
2494             self.assertTrue(s2.dumpPython() == "cms.Sequence(cms.Task(process.m1, process.m2, process.m3))\n")
2495 
2496             t1 = Task(m1,m2)
2497             t2 = Task(m1,m3,t1)
2498             t3 = t2.expandAndClone()
2499             self.assertTrue(t3.dumpPython() == "cms.Task(process.m1, process.m2, process.m3)\n")
2500             t4 = Task()
2501             t5 = t4.expandAndClone()
2502             self.assertTrue(t5.dumpPython() == "cms.Task()\n")
2503             #ConditionalTask
2504             s1 = Sequence(m1*~m2*m1*m2*ignore(m2))
2505             s2 = Sequence(m1*m2)
2506             s3 = Sequence(~m1*s2)
2507             p = Path(s1+s3, ConditionalTask(m6))
2508             p2 = p.expandAndClone()
2509             l[:] = []
2510             p2.visit(namesVisitor)
2511             self.assertEqual(l, ['m1', '!m2', 'm1', 'm2', '-m2', '!m1', 'm1', 'm2'])
2512             self.assertEqual(p2.dumpPython(), "cms.Path(process.m1+~process.m2+process.m1+process.m2+cms.ignore(process.m2)+~process.m1+process.m1+process.m2, cms.ConditionalTask(process.m6))\n")
2513 
2514             s2 = Sequence(m1*m2, ConditionalTask(m9))
2515             s3 = Sequence(~m1*s2)
2516             ct8 = ConditionalTask(m8)
2517             ct8.setLabel("ct8")
2518             p = Path(s1+s3, ConditionalTask(m6, ConditionalTask(m7, ct8)))
2519             p2 = p.expandAndClone()
2520             l[:] = []
2521             p2.visit(namesVisitor)
2522             self.assertEqual(l, ['m1', '!m2', 'm1', 'm2', '-m2', '!m1', 'm1', 'm2'])
2523             self.assertEqual(p2.dumpPython(), "cms.Path(process.m1+~process.m2+process.m1+process.m2+cms.ignore(process.m2)+~process.m1+process.m1+process.m2, cms.ConditionalTask(process.m6, process.m7, process.m8, process.m9))\n")
2524 
2525             t1 = ConditionalTask(m1,m2,m3)
2526             s1 = Sequence(t1)
2527             s2 = s1.expandAndClone()
2528             l[:] = []
2529             s2.visit(namesVisitor)
2530             self.assertEqual(l, [])
2531             self.assertEqual(s2.dumpPython(), "cms.Sequence(cms.ConditionalTask(process.m1, process.m2, process.m3))\n")
2532 
2533             t1 = ConditionalTask(m1,m2)
2534             t2 = ConditionalTask(m1,m3,t1)
2535             t3 = t2.expandAndClone()
2536             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.m1, process.m2, process.m3)\n")
2537             t4 = ConditionalTask()
2538             t5 = t4.expandAndClone()
2539             self.assertTrue(t5.dumpPython() == "cms.ConditionalTask()\n")
2540 
2541         def testAdd(self):
2542             m1 = DummyModule("m1")
2543             m2 = DummyModule("m2")
2544             m3 = DummyModule("m3")
2545             m4 = DummyModule("m4")
2546             s1 = Sequence(m1)
2547             s3 = Sequence(m3+ignore(m4))
2548             p = Path(s1)
2549             p += ~m2
2550             p *= s3
2551 
2552             l = []
2553             namesVisitor = DecoratedNodeNameVisitor(l)
2554             p.visit(namesVisitor)
2555             self.assertEqual(l, ['m1', '!m2', 'm3', '-m4'])
2556 
2557             s4 = Sequence()
2558             s4 +=m1
2559             l[:]=[]; s1.visit(namesVisitor); self.assertEqual(l,['m1'])
2560             self.assertEqual(s4.dumpPython(),"cms.Sequence(process.m1)\n")
2561             s4 = Sequence()
2562             s4 *=m1
2563             l[:]=[]; s1.visit(namesVisitor); self.assertEqual(l,['m1'])
2564             self.assertEqual(s4.dumpPython(),"cms.Sequence(process.m1)\n")
2565 
2566 
2567         def testRemove(self):
2568             m1 = DummyModule("m1")
2569             m2 = DummyModule("m2")
2570             m3 = DummyModule("m3")
2571             m4 = DummyModule("m4")
2572             s1 = Sequence(m1*m2+~m3)
2573             s2 = Sequence(m1*s1)
2574             l = []
2575             namesVisitor = DecoratedNodeNameVisitor(l)
2576             d = {'m1':m1 ,'m2':m2, 'm3':m3,'s1':s1, 's2':s2}
2577             l[:] = []; s1.visit(namesVisitor); self.assertEqual(l,['m1', 'm2', '!m3'])
2578             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m1', 'm1', 'm2', '!m3'])
2579             s1.remove(m2)
2580             l[:] = []; s1.visit(namesVisitor); self.assertEqual(l,['m1', '!m3'])
2581             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m1', 'm1', '!m3'])
2582             s2.remove(m3)
2583             l[:] = []; s1.visit(namesVisitor); self.assertEqual(l,['m1', '!m3'])
2584             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m1', 'm1'])
2585             s1 = Sequence( m1 + m2 + m1 + m2 )
2586             l[:] = []; s1.visit(namesVisitor); self.assertEqual(l,['m1', 'm2', 'm1', 'm2'])
2587             s1.remove(m2)
2588             l[:] = []; s1.visit(namesVisitor); self.assertEqual(l,['m1', 'm1', 'm2'])
2589             s1 = Sequence( m1 + m3 )
2590             s2 = Sequence( m2 + ignore(m3) + s1 + m3 )
2591             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m2', '-m3', 'm1', 'm3', 'm3'])
2592             s2.remove(s1)
2593             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m2', '-m3', 'm3'])
2594             s2.remove(m3)
2595             l[:] = []; s2.visit(namesVisitor); self.assertEqual(l,['m2','m3'])
2596             s1 = Sequence(m1*m2*m3)
2597             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2+process.m3)\n")
2598             s1.remove(m2)
2599             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m3)\n")
2600             s1 = Sequence(m1+m2+m3)
2601             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2+process.m3)\n")
2602             s1.remove(m2)
2603             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m3)\n")
2604             s1 = Sequence(m1*m2+m3)
2605             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2+process.m3)\n")
2606             s1.remove(m2)
2607             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m3)\n")
2608             s1 = Sequence(m1+m2*m3)
2609             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2+process.m3)\n")
2610             s1.remove(m2)
2611             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m3)\n")
2612             s1.remove(m1)
2613             s1.remove(m3)
2614             l[:]=[]; s1.visit(namesVisitor); self.assertEqual(l,[])
2615             self.assertEqual(s1.dumpPython(), "cms.Sequence()\n")
2616             s3 = Sequence(m1)
2617             s3.remove(m1)
2618             l[:]=[]; s3.visit(namesVisitor); self.assertEqual(l,[])
2619             self.assertEqual(s3.dumpPython(), "cms.Sequence()\n")
2620             s3 = Sequence(m1)
2621             s4 = Sequence(s3)
2622             s4.remove(m1)
2623             l[:]=[]; s4.visit(namesVisitor); self.assertEqual(l,[])
2624             self.assertEqual(s4.dumpPython(), "cms.Sequence()\n")
2625             #Task
2626             s1 = Sequence(m1+m2, Task(m3), Task(m4))
2627             s1.remove(m4)
2628             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2, cms.Task(process.m3))\n")
2629             s1 = Sequence(m1+m2+Sequence(Task(m3,m4), Task(m3), Task(m4)))
2630             s1.remove(m4)
2631             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2, cms.Task(process.m3), cms.Task(process.m4))\n")
2632             t1 = Task(m1)
2633             t1.setLabel("t1")
2634             t2 = Task(m2,t1)
2635             t2.setLabel("t2")
2636             t3 = Task(t1,t2,m1)
2637             t3.remove(m1)
2638             self.assertTrue(t3.dumpPython() == "cms.Task(process.m1, process.t2)\n")
2639             t3.remove(m1)
2640             self.assertTrue(t3.dumpPython() == "cms.Task(process.m1, process.m2)\n")
2641             t3.remove(m1)
2642             self.assertTrue(t3.dumpPython() == "cms.Task(process.m2)\n")
2643             t3.remove(m2)
2644             self.assertTrue(t3.dumpPython() == "cms.Task()\n")
2645             #ConditionalTask
2646             s1 = Sequence(m1+m2, ConditionalTask(m3), ConditionalTask(m4))
2647             s1.remove(m4)
2648             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2, cms.ConditionalTask(process.m3))\n")
2649             s1 = Sequence(m1+m2+Sequence(ConditionalTask(m3,m4), ConditionalTask(m3), ConditionalTask(m4)))
2650             s1.remove(m4)
2651             self.assertEqual(s1.dumpPython(), "cms.Sequence(process.m1+process.m2, cms.ConditionalTask(process.m3), cms.ConditionalTask(process.m4))\n")
2652             t1 = ConditionalTask(m1)
2653             t1.setLabel("t1")
2654             t2 = ConditionalTask(m2,t1)
2655             t2.setLabel("t2")
2656             t3 = ConditionalTask(t1,t2,m1)
2657             t3.remove(m1)
2658             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.m1, process.t2)\n")
2659             t3.remove(m1)
2660             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.m1, process.m2)\n")
2661             t3.remove(m1)
2662             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.m2)\n")
2663             t3.remove(m2)
2664             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask()\n")
2665             #FinalPath
2666             fp = FinalPath(m1+m2)
2667             fp.remove(m1)
2668             self.assertEqual(fp.dumpPython(), "cms.FinalPath(process.m2)\n")
2669             fp = FinalPath(m1)
2670             fp.remove(m1)
2671             self.assertEqual(fp.dumpPython(), "cms.FinalPath()\n")
2672 
2673         def testCopyAndExclude(self):
2674             a = DummyModule("a")
2675             b = DummyModule("b")
2676             c = DummyModule("c")
2677             d = DummyModule("d")
2678             s = Sequence(a+b+c)
2679             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2680             s = Sequence(a+b+c+d)
2681             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2682             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2683             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+process.d)\n")
2684             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2685             s=Sequence(a*b+c+d)
2686             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2687             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2688             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+process.d)\n")
2689             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2690             s = Sequence(a+b*c+d)
2691             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2692             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2693             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+process.d)\n")
2694             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2695             s2 = Sequence(a+b)
2696             s = Sequence(c+s2+d)
2697             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.c+process.b+process.d)\n")
2698             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.c+process.a+process.d)\n")
2699             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence((process.a+process.b)+process.d)\n")
2700             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.c+(process.a+process.b))\n")
2701             self.assertEqual(s.copyAndExclude([a,b]).dumpPython(),"cms.Sequence(process.c+process.d)\n")
2702             s3 = s.copyAndExclude([c])
2703             s2.remove(a)
2704             self.assertEqual(s3.dumpPython(),"cms.Sequence((process.b)+process.d)\n")
2705             s4 = s.copyAndExclude([a,b])
2706             seqs = []
2707             sequenceVisitor = SequenceVisitor(seqs)
2708             s.visit(sequenceVisitor)
2709             self.assertEqual(len(seqs),1)
2710             seqs[:] = []
2711             s4.visit(sequenceVisitor)
2712             self.assertEqual(len(seqs),0)
2713             self.assertEqual(s4.dumpPython(),"cms.Sequence(process.c+process.d)\n")
2714             holder = SequencePlaceholder("x")
2715             s3 = Sequence(b+d,Task(a))
2716             s2 = Sequence(a+b+holder+s3)
2717             s = Sequence(c+s2+d)
2718             seqs[:] = []
2719             s.visit(sequenceVisitor)
2720             self.assertTrue(seqs == [s2,s3])
2721             s2 = Sequence(a+b+holder)
2722             s = Sequence(c+s2+d)
2723             self.assertEqual(s.copyAndExclude([holder]).dumpPython(),"cms.Sequence(process.c+process.a+process.b+process.d)\n")
2724             s2 = Sequence(a+b+c)
2725             s = Sequence(s2+d)
2726             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2727             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2728             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+process.d)\n")
2729             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence((process.a+process.b+process.c))\n")
2730             self.assertEqual(s.copyAndExclude([s2]).dumpPython(),"cms.Sequence(process.d)\n")
2731             s2 = Sequence(a+b+c)
2732             s = Sequence(s2*d)
2733             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2734             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2735             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+process.d)\n")
2736             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence((process.a+process.b+process.c))\n")
2737             self.assertEqual(s.copyAndExclude([a,b,c]).dumpPython(),"cms.Sequence(process.d)\n")
2738             s = Sequence(ignore(a)+b+c+d)
2739             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2740             self.assertEqual(s.copyAndExclude([ignore(a)]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2741             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(cms.ignore(process.a)+process.c+process.d)\n")
2742             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(cms.ignore(process.a)+process.b+process.d)\n")
2743             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(cms.ignore(process.a)+process.b+process.c)\n")
2744             s = Sequence(a+ignore(b)+c+d)
2745             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(cms.ignore(process.b)+process.c+process.d)\n")
2746             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2747             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+cms.ignore(process.b)+process.d)\n")
2748             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+cms.ignore(process.b)+process.c)\n")
2749             s = Sequence(a+b+c+ignore(d))
2750             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+cms.ignore(process.d))\n")
2751             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+cms.ignore(process.d))\n")
2752             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+cms.ignore(process.d))\n")
2753             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2754             s = Sequence(~a+b+c+d)
2755             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+process.d)\n")
2756             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(~process.a+process.c+process.d)\n")
2757             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(~process.a+process.b+process.d)\n")
2758             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(~process.a+process.b+process.c)\n")
2759             s = Sequence(a+~b+c+d)
2760             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(~process.b+process.c+process.d)\n")
2761             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2762             self.assertEqual(s.copyAndExclude([~b]).dumpPython(),"cms.Sequence(process.a+process.c+process.d)\n")
2763             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+~process.b+process.d)\n")
2764             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+~process.b+process.c)\n")
2765             s = Sequence(a+b+c+~d)
2766             self.assertEqual(s.copyAndExclude([a]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d)\n")
2767             self.assertEqual(s.copyAndExclude([b]).dumpPython(),"cms.Sequence(process.a+process.c+~process.d)\n")
2768             self.assertEqual(s.copyAndExclude([c]).dumpPython(),"cms.Sequence(process.a+process.b+~process.d)\n")
2769             self.assertEqual(s.copyAndExclude([d]).dumpPython(),"cms.Sequence(process.a+process.b+process.c)\n")
2770             self.assertEqual(s.copyAndExclude([a,b,c,d]).dumpPython(),"cms.Sequence()\n")
2771 
2772             #Task
2773             e = DummyModule("e")
2774             f = DummyModule("f")
2775             g = DummyModule("g")
2776             h = DummyModule("h")
2777             t1 = Task(h)
2778             s = Sequence(a+b+c+~d, Task(e,f,Task(g,t1)))
2779             self.assertEqual(s.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.Task(process.e, process.f, process.g))\n")
2780             self.assertEqual(s.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.Task(process.e, process.f, process.g))\n")
2781             self.assertEqual(s.copyAndExclude([a,e,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.Task(process.f, process.g))\n")
2782             self.assertEqual(s.copyAndExclude([a,e,f,g,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d)\n")
2783             self.assertEqual(s.copyAndExclude([a,b,c,d]).dumpPython(),"cms.Sequence(cms.Task(process.e, process.f, process.g, process.h))\n")
2784             self.assertEqual(s.copyAndExclude([t1]).dumpPython(),"cms.Sequence(process.a+process.b+process.c+~process.d, cms.Task(process.e, process.f, process.g))\n")
2785             taskList = []
2786             taskVisitor = TaskVisitor(taskList)
2787             s.visit(taskVisitor)
2788             self.assertEqual(len(taskList),3)
2789             s2 = s.copyAndExclude([g,h])
2790             taskList[:] = []
2791             s2.visit(taskVisitor)
2792             self.assertEqual(len(taskList),1)
2793             t2 = Task(t1)
2794             taskList[:] = []
2795             t2.visit(taskVisitor)
2796             self.assertEqual(taskList[0],t1)
2797             s3 = Sequence(s)
2798             self.assertEqual(s3.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.Task(process.e, process.f, process.g))\n")
2799             s4 = Sequence(s)
2800             self.assertEqual(s4.copyAndExclude([a,b,c,d,e,f,g,h]).dumpPython(),"cms.Sequence()\n")
2801             t1 = Task(e,f)
2802             t11 = Task(a)
2803             t11.setLabel("t11")
2804             t2 = Task(g,t1,h,t11)
2805             t3 = t2.copyAndExclude([e,h])
2806             self.assertTrue(t3.dumpPython() == "cms.Task(process.f, process.g, process.t11)\n")
2807             t4 = t2.copyAndExclude([e,f,g,h,a])
2808             self.assertTrue(t4.dumpPython() == "cms.Task()\n")
2809             #ConditionalTask
2810             t1 = ConditionalTask(h)
2811             s = Sequence(a+b+c+~d, ConditionalTask(e,f,ConditionalTask(g,t1)))
2812             self.assertEqual(s.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.ConditionalTask(process.e, process.f, process.g))\n")
2813             self.assertEqual(s.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.ConditionalTask(process.e, process.f, process.g))\n")
2814             self.assertEqual(s.copyAndExclude([a,e,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.ConditionalTask(process.f, process.g))\n")
2815             self.assertEqual(s.copyAndExclude([a,e,f,g,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d)\n")
2816             self.assertEqual(s.copyAndExclude([a,b,c,d]).dumpPython(),"cms.Sequence(cms.ConditionalTask(process.e, process.f, process.g, process.h))\n")
2817             self.assertEqual(s.copyAndExclude([t1]).dumpPython(),"cms.Sequence(process.a+process.b+process.c+~process.d, cms.ConditionalTask(process.e, process.f, process.g))\n")
2818             taskList = []
2819             taskVisitor = ConditionalTaskVisitor(taskList)
2820             s.visit(taskVisitor)
2821             self.assertEqual(len(taskList),3)
2822             s2 = s.copyAndExclude([g,h])
2823             taskList[:] = []
2824             s2.visit(taskVisitor)
2825             self.assertEqual(len(taskList),1)
2826             t2 = ConditionalTask(t1)
2827             taskList[:] = []
2828             t2.visit(taskVisitor)
2829             self.assertEqual(taskList[0],t1)
2830             s3 = Sequence(s)
2831             self.assertEqual(s3.copyAndExclude([a,h]).dumpPython(),"cms.Sequence(process.b+process.c+~process.d, cms.ConditionalTask(process.e, process.f, process.g))\n")
2832             s4 = Sequence(s)
2833             self.assertEqual(s4.copyAndExclude([a,b,c,d,e,f,g,h]).dumpPython(),"cms.Sequence()\n")
2834             t1 = ConditionalTask(e,f)
2835             t11 = ConditionalTask(a)
2836             t11.setLabel("t11")
2837             t2 = ConditionalTask(g,t1,h,t11)
2838             t3 = t2.copyAndExclude([e,h])
2839             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.f, process.g, process.t11)\n")
2840             t4 = t2.copyAndExclude([e,f,g,h,a])
2841             self.assertEqual(t4.dumpPython(), "cms.ConditionalTask()\n")
2842 
2843         def testSequenceTypeChecks(self):
2844             m1 = DummyModule("m1")
2845             m2 = DummyModule("m2")
2846             s1 = Sequence(m1*m2)
2847             def testRaise():
2848                 s1.something = 1
2849             self.assertRaises(AttributeError,testRaise)
2850             def testRaise2():
2851                 s2 = Sequence(m1*None)
2852             self.assertRaises(TypeError,testRaise2)
2853         def testCopy(self):
2854             a = DummyModule("a")
2855             b = DummyModule("b")
2856             c = DummyModule("c")
2857             p1 = Path(a+b+c)
2858             p2 = p1.copy()
2859             e = DummyModule("e")
2860             p2.replace(b,e)
2861             self.assertEqual(p1.dumpPython(),"cms.Path(process.a+process.b+process.c)\n")
2862             self.assertEqual(p2.dumpPython(),"cms.Path(process.a+process.e+process.c)\n")
2863             p1 = Path(a+b+c)
2864             p2 = p1.copy()
2865             p1 += e
2866             self.assertEqual(p1.dumpPython(),"cms.Path(process.a+process.b+process.c+process.e)\n")
2867             self.assertEqual(p2.dumpPython(),"cms.Path(process.a+process.b+process.c)\n")
2868             #Task
2869             t1 = Task(a, b)
2870             t2 = t1.copy()
2871             self.assertTrue(t1.dumpPython() == t2.dumpPython())
2872             t1Contents = list(t1._collection)
2873             t2Contents = list(t2._collection)
2874             self.assertTrue(id(t1Contents[0]) == id(t2Contents[0]))
2875             self.assertTrue(id(t1Contents[1]) == id(t2Contents[1]))
2876             self.assertTrue(id(t1._collection) != id(t2._collection))
2877             #ConditionalTask
2878             t1 = ConditionalTask(a, b)
2879             t2 = t1.copy()
2880             self.assertTrue(t1.dumpPython() == t2.dumpPython())
2881             t1Contents = list(t1._collection)
2882             t2Contents = list(t2._collection)
2883             self.assertTrue(id(t1Contents[0]) == id(t2Contents[0]))
2884             self.assertTrue(id(t1Contents[1]) == id(t2Contents[1]))
2885             self.assertTrue(id(t1._collection) != id(t2._collection))
2886 
2887         def testCopyAndAdd(self):
2888             a = DummyModule("a")
2889             b = DummyModule("b")
2890             c = DummyModule("c")
2891             d = DummyModule("d")
2892             e = DummyModule("e")
2893             #Task
2894             t1 = Task(a, b, c)
2895             self.assertEqual(t1.dumpPython(), "cms.Task(process.a, process.b, process.c)\n")
2896             t2 = t1.copyAndAdd(d, e)
2897             self.assertEqual(t1.dumpPython(), "cms.Task(process.a, process.b, process.c)\n")
2898             self.assertEqual(t2.dumpPython(), "cms.Task(process.a, process.b, process.c, process.d, process.e)\n")
2899             t3 = t2.copyAndExclude([b])
2900             self.assertEqual(t1.dumpPython(), "cms.Task(process.a, process.b, process.c)\n")
2901             self.assertEqual(t2.dumpPython(), "cms.Task(process.a, process.b, process.c, process.d, process.e)\n")
2902             self.assertEqual(t3.dumpPython(), "cms.Task(process.a, process.c, process.d, process.e)\n")
2903             t4 = t1.copyAndExclude([b]).copyAndAdd(d)
2904             self.assertEqual(t4.dumpPython(), "cms.Task(process.a, process.c, process.d)\n")
2905             t5 = t2.copyAndExclude([b]).copyAndAdd(d)
2906             self.assertEqual(t5.dumpPython(), "cms.Task(process.a, process.c, process.d, process.e)\n")
2907             t6 = t4.copyAndAdd(Task(b))
2908             self.assertEqual(t6.dumpPython(), "cms.Task(process.a, process.b, process.c, process.d)\n")
2909             #ConditionalTask
2910             t1 = ConditionalTask(a, b, c)
2911             self.assertEqual(t1.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c)\n")
2912             t2 = t1.copyAndAdd(d, e)
2913             self.assertEqual(t1.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c)\n")
2914             self.assertEqual(t2.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c, process.d, process.e)\n")
2915             t3 = t2.copyAndExclude([b])
2916             self.assertEqual(t1.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c)\n")
2917             self.assertEqual(t2.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c, process.d, process.e)\n")
2918             self.assertEqual(t3.dumpPython(), "cms.ConditionalTask(process.a, process.c, process.d, process.e)\n")
2919             t4 = t1.copyAndExclude([b]).copyAndAdd(d)
2920             self.assertEqual(t4.dumpPython(), "cms.ConditionalTask(process.a, process.c, process.d)\n")
2921             t5 = t2.copyAndExclude([b]).copyAndAdd(d)
2922             self.assertEqual(t5.dumpPython(), "cms.ConditionalTask(process.a, process.c, process.d, process.e)\n")
2923             t6 = t4.copyAndAdd(Task(b))
2924             self.assertEqual(t6.dumpPython(), "cms.ConditionalTask(process.a, process.b, process.c, process.d)\n")
2925 
2926         def testInsertInto(self):
2927             from FWCore.ParameterSet.Types import vstring
2928             class TestPSet(object):
2929                 def __init__(self):
2930                     self._dict = dict()
2931                 def addVString(self,isTracked,label,value):
2932                     self._dict[label]=value
2933             a = DummyModule("a")
2934             b = DummyModule("b")
2935             c = DummyModule("c")
2936             d = DummyModule("d")
2937             p = Path(a+b+c+d)
2938             decoratedList = []
2939             lister = DecoratedNodeNameVisitor(decoratedList)
2940             p.visit(lister)
2941             ps = TestPSet()
2942             p.insertInto(ps,"p",decoratedList)
2943             self.assertEqual(ps._dict, {"p":vstring("a","b","c","d")})
2944             s = Sequence(b+c)
2945             p = Path(a+s+d)
2946             decoratedList[:] = []
2947             p.visit(lister)
2948             ps = TestPSet()
2949             p.insertInto(ps,"p",decoratedList)
2950             self.assertEqual(ps._dict, {"p":vstring("a","b","c","d")})
2951 
2952     unittest.main()