Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-12-01 23:40:20

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