CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_7/src/FWCore/ParameterSet/python/Config.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 ### command line options helper
00004 from  Options import Options
00005 options = Options()
00006 
00007 
00008 ## imports
00009 import sys
00010 from Mixins import PrintOptions,_ParameterTypeBase,_SimpleParameterTypeBase, _Parameterizable, _ConfigureComponent, _TypedParameterizable, _Labelable,  _Unlabelable,  _ValidatingListBase
00011 from Mixins import *
00012 from Types import *
00013 from Modules import *
00014 from Modules import _Module
00015 from SequenceTypes import *
00016 from SequenceTypes import _ModuleSequenceType, _Sequenceable  #extend needs it
00017 from SequenceVisitors import PathValidator, EndPathValidator
00018 from Utilities import *
00019 import DictTypes
00020 
00021 from ExceptionHandling import *
00022 
00023 #when building RECO paths we have hit the default recursion limit
00024 if sys.getrecursionlimit()<5000:
00025    sys.setrecursionlimit(5000)
00026 
00027 def checkImportPermission(minLevel = 2, allowedPatterns = []):
00028     """
00029     Raise an exception if called by special config files. This checks
00030     the call or import stack for the importing file. An exception is raised if
00031     the importing module is not in allowedPatterns and if it is called too deeply:
00032     minLevel = 2: inclusion by top lvel cfg only
00033     minLevel = 1: No inclusion allowed
00034     allowedPatterns = ['Module1','Module2/SubModule1'] allows import
00035     by any module in Module1 or Submodule1
00036     """
00037 
00038     import inspect
00039     import os
00040 
00041     ignorePatterns = ['FWCore/ParameterSet/Config.py','<string>']
00042     CMSSWPath = [os.environ['CMSSW_BASE'],os.environ['CMSSW_RELEASE_BASE']]
00043 
00044     # Filter the stack to things in CMSSWPath and not in ignorePatterns
00045     trueStack = []
00046     for item in inspect.stack():
00047         inPath = False
00048         ignore = False
00049 
00050         for pattern in CMSSWPath:
00051             if item[1].find(pattern) != -1:
00052                 inPath = True
00053                 break
00054         if item[1].find('/') == -1: # The base file, no path
00055             inPath = True
00056 
00057         for pattern in ignorePatterns:
00058             if item[1].find(pattern) != -1:
00059                 ignore = True
00060                 break
00061 
00062         if inPath and not ignore:
00063             trueStack.append(item[1])
00064 
00065     importedFile = trueStack[0]
00066     importedBy   = ''
00067     if len(trueStack) > 1:
00068         importedBy = trueStack[1]
00069 
00070     for pattern in allowedPatterns:
00071         if importedBy.find(pattern) > -1:
00072             return True
00073 
00074     if len(trueStack) <= minLevel: # Imported directly
00075         return True
00076 
00077     raise ImportError("Inclusion of %s is allowed only by cfg or specified cfi files."
00078                       % importedFile)
00079 
00080 def findProcess(module):
00081     """Look inside the module and find the Processes it contains"""
00082     class Temp(object):
00083         pass
00084     process = None
00085     if isinstance(module,dict):
00086         if 'process' in module:
00087             p = module['process']
00088             module = Temp()
00089             module.process = p
00090     if hasattr(module,'process'):
00091         if isinstance(module.process,Process):
00092             process = module.process
00093         else:
00094             raise RuntimeError("The attribute named 'process' does not inherit from the Process class")
00095     else:
00096         raise RuntimeError("no 'process' attribute found in the module, please add one")
00097     return process
00098 
00099 
00100 class Process(object):
00101     """Root class for a CMS configuration process"""
00102     def __init__(self,name):
00103         """The argument 'name' will be the name applied to this Process"""
00104         self.__dict__['_Process__name'] = name
00105         if not name.isalnum():
00106             raise RuntimeError("Error: The process name is an empty string or contains non-alphanumeric characters")
00107         self.__dict__['_Process__filters'] = {}
00108         self.__dict__['_Process__producers'] = {}
00109         self.__dict__['_Process__source'] = None
00110         self.__dict__['_Process__looper'] = None
00111         self.__dict__['_Process__subProcess'] = None
00112         self.__dict__['_Process__schedule'] = None
00113         self.__dict__['_Process__analyzers'] = {}
00114         self.__dict__['_Process__outputmodules'] = {}
00115         self.__dict__['_Process__paths'] = DictTypes.SortedKeysDict()    # have to keep the order
00116         self.__dict__['_Process__endpaths'] = DictTypes.SortedKeysDict() # of definition
00117         self.__dict__['_Process__sequences'] = {}
00118         self.__dict__['_Process__services'] = {}
00119         self.__dict__['_Process__essources'] = {}
00120         self.__dict__['_Process__esproducers'] = {}
00121         self.__dict__['_Process__esprefers'] = {}
00122         self.__dict__['_Process__aliases'] = {}
00123         self.__dict__['_Process__psets']={}
00124         self.__dict__['_Process__vpsets']={}
00125         self.__dict__['_cloneToObjectDict'] = {}
00126         # policy switch to avoid object overwriting during extend/load
00127         self.__dict__['_Process__InExtendCall'] = False
00128         self.__dict__['_Process__partialschedules'] = {}
00129         self.__isStrict = False
00130 
00131     def setStrict(self, value):
00132         self.__isStrict = value
00133         _Module.__isStrict__ = True
00134 
00135     # some user-friendly methods for command-line browsing
00136     def producerNames(self):
00137         """Returns a string containing all the EDProducer labels separated by a blank"""
00138         return ' '.join(self.producers_().keys())
00139     def analyzerNames(self):
00140         """Returns a string containing all the EDAnalyzer labels separated by a blank"""
00141         return ' '.join(self.analyzers_().keys())
00142     def filterNames(self):
00143         """Returns a string containing all the EDFilter labels separated by a blank"""
00144         return ' '.join(self.filters_().keys())
00145     def pathNames(self):
00146         """Returns a string containing all the Path names separated by a blank"""
00147         return ' '.join(self.paths_().keys())
00148 
00149     def __setstate__(self, pkldict):
00150         """
00151         Unpickling hook.
00152 
00153         Since cloneToObjectDict stores a hash of objects by their
00154         id() it needs to be updated when unpickling to use the
00155         new object id values instantiated during the unpickle.
00156 
00157         """
00158         self.__dict__.update(pkldict)
00159         tmpDict = {}
00160         for value in self._cloneToObjectDict.values():
00161             tmpDict[id(value)] = value
00162         self.__dict__['_cloneToObjectDict'] = tmpDict
00163 
00164 
00165 
00166     def filters_(self):
00167         """returns a dict of the filters which have been added to the Process"""
00168         return DictTypes.FixedKeysDict(self.__filters)
00169     filters = property(filters_, doc="dictionary containing the filters for the process")
00170     def name_(self):
00171         return self.__name
00172     def setName_(self,name):
00173         if not name.isalnum():
00174             raise RuntimeError("Error: The process name is an empty string or contains non-alphanumeric characters")
00175         self.__dict__['_Process__name'] = name
00176     process = property(name_,setName_, doc="name of the process")
00177     def producers_(self):
00178         """returns a dict of the producers which have been added to the Process"""
00179         return DictTypes.FixedKeysDict(self.__producers)
00180     producers = property(producers_,doc="dictionary containing the producers for the process")
00181     def source_(self):
00182         """returns the source which has been added to the Process or None if none have been added"""
00183         return self.__source
00184     def setSource_(self,src):
00185         self._placeSource('source',src)
00186     source = property(source_,setSource_,doc='the main source or None if not set')
00187     def looper_(self):
00188         """returns the looper which has been added to the Process or None if none have been added"""
00189         return self.__looper
00190     def setLooper_(self,lpr):
00191         self._placeLooper('looper',lpr)
00192     looper = property(looper_,setLooper_,doc='the main looper or None if not set')
00193     def subProcess_(self):
00194         """returns the sub-process which has been added to the Process or None if none have been added"""
00195         return self.__subProcess
00196     def setSubProcess_(self,lpr):
00197         self._placeSubProcess('subProcess',lpr)
00198     subProcess = property(subProcess_,setSubProcess_,doc='the SubProcess or None if not set')
00199     def analyzers_(self):
00200         """returns a dict of the analyzers which have been added to the Process"""
00201         return DictTypes.FixedKeysDict(self.__analyzers)
00202     analyzers = property(analyzers_,doc="dictionary containing the analyzers for the process")
00203     def outputModules_(self):
00204         """returns a dict of the output modules which have been added to the Process"""
00205         return DictTypes.FixedKeysDict(self.__outputmodules)
00206     outputModules = property(outputModules_,doc="dictionary containing the output_modules for the process")
00207     def paths_(self):
00208         """returns a dict of the paths which have been added to the Process"""
00209         return DictTypes.SortedAndFixedKeysDict(self.__paths)
00210     paths = property(paths_,doc="dictionary containing the paths for the process")
00211     def endpaths_(self):
00212         """returns a dict of the endpaths which have been added to the Process"""
00213         return DictTypes.SortedAndFixedKeysDict(self.__endpaths)
00214     endpaths = property(endpaths_,doc="dictionary containing the endpaths for the process")
00215     def sequences_(self):
00216         """returns a dict of the sequences which have been added to the Process"""
00217         return DictTypes.FixedKeysDict(self.__sequences)
00218     sequences = property(sequences_,doc="dictionary containing the sequences for the process")
00219     def schedule_(self):
00220         """returns the schedule which has been added to the Process or None if none have been added"""
00221         return self.__schedule
00222     def setPartialSchedule_(self,sch,label):
00223         if label == "schedule":
00224             self.setSchedule_(sch)
00225         else:
00226             self._place(label, sch, self.__partialschedules)
00227     def setSchedule_(self,sch):
00228                 # See if every module has been inserted into the process
00229         index = 0
00230         try:
00231             for p in sch:
00232                p.label_()
00233                index +=1
00234         except:
00235             raise RuntimeError("The path at index "+str(index)+" in the Schedule was not attached to the process.")
00236 
00237         self.__dict__['_Process__schedule'] = sch
00238     schedule = property(schedule_,setSchedule_,doc='the schedule or None if not set')
00239     def services_(self):
00240         """returns a dict of the services which have been added to the Process"""
00241         return DictTypes.FixedKeysDict(self.__services)
00242     services = property(services_,doc="dictionary containing the services for the process")
00243     def es_producers_(self):
00244         """returns a dict of the esproducers which have been added to the Process"""
00245         return DictTypes.FixedKeysDict(self.__esproducers)
00246     es_producers = property(es_producers_,doc="dictionary containing the es_producers for the process")
00247     def es_sources_(self):
00248         """returns a the es_sources which have been added to the Process"""
00249         return DictTypes.FixedKeysDict(self.__essources)
00250     es_sources = property(es_sources_,doc="dictionary containing the es_sources for the process")
00251     def es_prefers_(self):
00252         """returns a dict of the es_prefers which have been added to the Process"""
00253         return DictTypes.FixedKeysDict(self.__esprefers)
00254     es_prefers = property(es_prefers_,doc="dictionary containing the es_prefers for the process")
00255     def aliases_(self):
00256         """returns a dict of the aliases that have been added to the Process"""
00257         return DictTypes.FixedKeysDict(self.__aliases)
00258     aliases = property(aliases_,doc="dictionary containing the aliases for the process")
00259     def psets_(self):
00260         """returns a dict of the PSets which have been added to the Process"""
00261         return DictTypes.FixedKeysDict(self.__psets)
00262     psets = property(psets_,doc="dictionary containing the PSets for the process")
00263     def vpsets_(self):
00264         """returns a dict of the VPSets which have been added to the Process"""
00265         return DictTypes.FixedKeysDict(self.__vpsets)
00266     vpsets = property(vpsets_,doc="dictionary containing the PSets for the process")
00267 
00268     def __setObjectLabel(self, object, newLabel) :
00269         if not object.hasLabel_() :
00270             object.setLabel(newLabel)
00271             return
00272         if newLabel == object.label_() :
00273             return
00274         if newLabel is None :
00275             object.setLabel(None)
00276             return
00277         if (hasattr(self, object.label_()) and id(getattr(self, object.label_())) == id(object)) :
00278             msg100 = "Attempting to change the label of an attribute of the Process\n"
00279             msg101 = "Old label = "+object.label_()+"  New label = "+newLabel+"\n"
00280             msg102 = "Type = "+str(type(object))+"\n"
00281             msg103 = "Some possible solutions:\n"
00282             msg104 = "  1. Clone modules instead of using simple assignment. Cloning is\n"
00283             msg105 = "  also preferred for other types when possible.\n"
00284             msg106 = "  2. Declare new names starting with an underscore if they are\n"
00285             msg107 = "  for temporaries you do not want propagated into the Process. The\n"
00286             msg108 = "  underscore tells \"from x import *\" and process.load not to import\n"
00287             msg109 = "  the name.\n"
00288             msg110 = "  3. Reorganize so the assigment is not necessary. Giving a second\n"
00289             msg111 = "  name to the same object usually causes confusion and problems.\n"
00290             msg112 = "  4. Compose Sequences: newName = cms.Sequence(oldName)\n"
00291             raise ValueError(msg100+msg101+msg102+msg103+msg104+msg105+msg106+msg107+msg108+msg109+msg110+msg111+msg112)
00292         object.setLabel(None)
00293         object.setLabel(newLabel)
00294 
00295     def __setattr__(self,name,value):
00296         # check if the name is well-formed (only _ and alphanumerics are allowed)
00297         if not name.replace('_','').isalnum():
00298             raise ValueError('The label '+name+' contains forbiden characters')
00299 
00300         # private variable exempt from all this
00301         if name.startswith('_Process__'):
00302             self.__dict__[name]=value
00303             return
00304         if not isinstance(value,_ConfigureComponent):
00305             raise TypeError("can only assign labels to an object which inherits from '_ConfigureComponent'\n"
00306                             +"an instance of "+str(type(value))+" will not work")
00307         if not isinstance(value,_Labelable) and not isinstance(value,Source) and not isinstance(value,Looper) and not isinstance(value,Schedule):
00308             if name == value.type_():
00309                 self.add_(value)
00310                 return
00311             else:
00312                 raise TypeError("an instance of "+str(type(value))+" can not be assigned the label '"+name+"'.\n"+
00313                                 "Please either use the label '"+value.type_()+" or use the 'add_' method instead.")
00314         #clone the item
00315         if self.__isStrict:
00316             newValue =value.copy()
00317             try:
00318               newValue._filename = value._filename
00319             except:
00320               pass
00321             value.setIsFrozen()
00322         else:
00323             newValue =value
00324         if not self._okToPlace(name, value, self.__dict__):
00325             newFile='top level config'
00326             if hasattr(value,'_filename'):
00327                newFile = value._filename
00328             oldFile='top level config'
00329             oldValue = getattr(self,name)
00330             if hasattr(oldValue,'_filename'):
00331                oldFile = oldValue._filename
00332             msg = "Trying to override definition of process."+name
00333             msg += "\n new object defined in: "+newFile
00334             msg += "\n existing object defined in: "+oldFile
00335             raise ValueError(msg)
00336         # remove the old object of the name (if there is one)
00337         if hasattr(self,name) and not (getattr(self,name)==newValue):
00338             # Compain if items in sequences from load() statements have
00339             # degeneratate names, but if the user overwrites a name in the
00340             # main config, replace it everywhere
00341             if isinstance(newValue, _Sequenceable):
00342                 if not self.__InExtendCall:
00343                    self._replaceInSequences(name, newValue)
00344                 else:
00345                    #should check to see if used in sequence before complaining
00346                    newFile='top level config'
00347                    if hasattr(value,'_filename'):
00348                       newFile = value._filename
00349                    oldFile='top level config'
00350                    oldValue = getattr(self,name)
00351                    if hasattr(oldValue,'_filename'):
00352                       oldFile = oldValue._filename
00353                    msg1 = "Trying to override definition of "+name+" while it is used by the sequence "
00354                    msg2 = "\n new object defined in: "+newFile
00355                    msg2 += "\n existing object defined in: "+oldFile
00356                    s = self.__findFirstSequenceUsingModule(self.sequences,oldValue)
00357                    if s is not None:
00358                       raise ValueError(msg1+s.label_()+msg2)
00359                    s = self.__findFirstSequenceUsingModule(self.paths,oldValue)
00360                    if s is not None:
00361                       raise ValueError(msg1+s.label_()+msg2)
00362                    s = self.__findFirstSequenceUsingModule(self.endpaths,oldValue)
00363                    if s is not None:
00364                       raise ValueError(msg1+s.label_()+msg2)
00365             self.__delattr__(name)
00366         self.__dict__[name]=newValue
00367         if isinstance(newValue,_Labelable):
00368             self.__setObjectLabel(newValue, name)
00369             self._cloneToObjectDict[id(value)] = newValue
00370             self._cloneToObjectDict[id(newValue)] = newValue
00371         #now put in proper bucket
00372         newValue._place(name,self)
00373     def __findFirstSequenceUsingModule(self,seqs,mod):
00374        """Given a container of sequences, find the first sequence containing mod
00375        and return the sequence. If no sequence is found, return None"""
00376        from FWCore.ParameterSet.SequenceTypes import ModuleNodeVisitor
00377        for sequenceable in seqs.itervalues():
00378           l = list()
00379           v = ModuleNodeVisitor(l)
00380           sequenceable.visit(v)
00381           if mod in l:
00382              return sequenceable
00383        return None
00384     def __delattr__(self,name):
00385         if not hasattr(self,name):
00386             raise KeyError('process does not know about '+name)
00387         elif name.startswith('_Process__'):
00388             raise ValueError('this attribute cannot be deleted')
00389         else:
00390             # we have to remove it from all dictionaries/registries
00391             dicts = [item for item in self.__dict__.values() if (type(item)==dict or type(item)==DictTypes.SortedKeysDict)]
00392             for reg in dicts:
00393                 if reg.has_key(name): del reg[name]
00394             # if it was a labelable object, the label needs to be removed
00395             obj = getattr(self,name)
00396             if isinstance(obj,_Labelable):
00397                 getattr(self,name).setLabel(None)
00398             # now remove it from the process itself
00399             try:
00400                 del self.__dict__[name]
00401             except:
00402                 pass
00403 
00404     def add_(self,value):
00405         """Allows addition of components which do not have to have a label, e.g. Services"""
00406         if not isinstance(value,_ConfigureComponent):
00407             raise TypeError
00408         if not isinstance(value,_Unlabelable):
00409             raise TypeError
00410         #clone the item
00411         #clone the item
00412         if self.__isStrict:
00413             newValue =value.copy()
00414             value.setIsFrozen()
00415         else:
00416             newValue =value
00417         newValue._place('',self)
00418 
00419     def _okToPlace(self, name, mod, d):
00420         if not self.__InExtendCall:
00421             # if going
00422             return True
00423         elif not self.__isStrict:
00424             return True
00425         elif name in d:
00426             # if there's an old copy, and the new one
00427             # hasn't been modified, we're done.  Still
00428             # not quite safe if something has been defined twice.
00429             #  Need to add checks
00430             if mod._isModified:
00431                 if d[name]._isModified:
00432                     return False
00433                 else:
00434                     return True
00435             else:
00436                 return True
00437         else:
00438             return True
00439 
00440     def _place(self, name, mod, d):
00441         if self._okToPlace(name, mod, d):
00442             if self.__isStrict and isinstance(mod, _ModuleSequenceType):
00443                 d[name] = mod._postProcessFixup(self._cloneToObjectDict)
00444             else:
00445                 d[name] = mod
00446             if isinstance(mod,_Labelable):
00447                 self.__setObjectLabel(mod, name)
00448     def _placeOutputModule(self,name,mod):
00449         self._place(name, mod, self.__outputmodules)
00450     def _placeProducer(self,name,mod):
00451         self._place(name, mod, self.__producers)
00452     def _placeFilter(self,name,mod):
00453         self._place(name, mod, self.__filters)
00454     def _placeAnalyzer(self,name,mod):
00455         self._place(name, mod, self.__analyzers)
00456     def _placePath(self,name,mod):
00457         self._validateSequence(mod, name)
00458         try:
00459             self._place(name, mod, self.__paths)
00460         except ModuleCloneError, msg:
00461             context = format_outerframe(4)
00462             raise Exception("%sThe module %s in path %s is unknown to the process %s." %(context, msg, name, self._Process__name))
00463     def _placeEndPath(self,name,mod):
00464         self._validateSequence(mod, name)
00465         try:
00466             self._place(name, mod, self.__endpaths)
00467         except ModuleCloneError, msg:
00468             context = format_outerframe(4)
00469             raise Exception("%sThe module %s in endpath %s is unknown to the process %s." %(context, msg, name, self._Process__name))
00470     def _placeSequence(self,name,mod):
00471         self._validateSequence(mod, name)
00472         self._place(name, mod, self.__sequences)
00473     def _placeESProducer(self,name,mod):
00474         self._place(name, mod, self.__esproducers)
00475     def _placeESPrefer(self,name,mod):
00476         self._place(name, mod, self.__esprefers)
00477     def _placeESSource(self,name,mod):
00478         self._place(name, mod, self.__essources)
00479     def _placeAlias(self,name,mod):
00480         self._place(name, mod, self.__aliases)
00481     def _placePSet(self,name,mod):
00482         self._place(name, mod, self.__psets)
00483     def _placeVPSet(self,name,mod):
00484         self._place(name, mod, self.__vpsets)
00485     def _placeSource(self,name,mod):
00486         """Allow the source to be referenced by 'source' or by type name"""
00487         if name != 'source':
00488             raise ValueError("The label '"+name+"' can not be used for a Source.  Only 'source' is allowed.")
00489         if self.__dict__['_Process__source'] is not None :
00490             del self.__dict__[self.__dict__['_Process__source'].type_()]
00491         self.__dict__['_Process__source'] = mod
00492         self.__dict__[mod.type_()] = mod
00493     def _placeLooper(self,name,mod):
00494         if name != 'looper':
00495             raise ValueError("The label '"+name+"' can not be used for a Looper.  Only 'looper' is allowed.")
00496         self.__dict__['_Process__looper'] = mod
00497         self.__dict__[mod.type_()] = mod
00498     def _placeSubProcess(self,name,mod):
00499         if name != 'subProcess':
00500             raise ValueError("The label '"+name+"' can not be used for a SubProcess.  Only 'subProcess' is allowed.")
00501         self.__dict__['_Process__subProcess'] = mod
00502         self.__dict__[mod.type_()] = mod
00503     def _placeService(self,typeName,mod):
00504         self._place(typeName, mod, self.__services)
00505         self.__dict__[typeName]=mod
00506     def load(self, moduleName):
00507         moduleName = moduleName.replace("/",".")
00508         module = __import__(moduleName)
00509         self.extend(sys.modules[moduleName])
00510     def extend(self,other,items=()):
00511         """Look in other and find types which we can use"""
00512         # enable explicit check to avoid overwriting of existing objects
00513         self.__dict__['_Process__InExtendCall'] = True
00514 
00515         seqs = dict()
00516         for name in dir(other):
00517             #'from XX import *' ignores these, and so should we.
00518             if name.startswith('_'):
00519                 continue
00520             item = getattr(other,name)
00521             if name == "source" or name == "looper" or name == "subProcess":
00522                 self.__setattr__(name,item)
00523             elif isinstance(item,_ModuleSequenceType):
00524                 seqs[name]=item
00525             elif isinstance(item,_Labelable):
00526                 self.__setattr__(name,item)
00527                 if not item.hasLabel_() :
00528                     item.setLabel(name)
00529             elif isinstance(item,Schedule):
00530                 self.__setattr__(name,item)
00531             elif isinstance(item,_Unlabelable):
00532                 self.add_(item)
00533 
00534         #now create a sequence which uses the newly made items
00535         for name in seqs.iterkeys():
00536             seq = seqs[name]
00537             #newSeq = seq.copy()
00538             #
00539             if id(seq) not in self._cloneToObjectDict:
00540                 self.__setattr__(name,seq)
00541             else:
00542                 newSeq = self._cloneToObjectDict[id(seq)]
00543                 self.__dict__[name]=newSeq
00544                 self.__setObjectLabel(newSeq, name)
00545                 #now put in proper bucket
00546                 newSeq._place(name,self)
00547         self.__dict__['_Process__InExtendCall'] = False
00548     def _dumpConfigNamedList(self,items,typeName,options):
00549         returnValue = ''
00550         for name,item in items:
00551             returnValue +=options.indentation()+typeName+' '+name+' = '+item.dumpConfig(options)
00552         return returnValue
00553     def _dumpConfigUnnamedList(self,items,typeName,options):
00554         returnValue = ''
00555         for name,item in items:
00556             returnValue +=options.indentation()+typeName+' = '+item.dumpConfig(options)
00557         return returnValue
00558     def _dumpConfigOptionallyNamedList(self,items,typeName,options):
00559         returnValue = ''
00560         for name,item in items:
00561             if name == item.type_():
00562                 name = ''
00563             returnValue +=options.indentation()+typeName+' '+name+' = '+item.dumpConfig(options)
00564         return returnValue
00565     def dumpConfig(self, options=PrintOptions()):
00566         """return a string containing the equivalent process defined using the old configuration language"""
00567         config = "process "+self.__name+" = {\n"
00568         options.indent()
00569         if self.source_():
00570             config += options.indentation()+"source = "+self.source_().dumpConfig(options)
00571         if self.looper_():
00572             config += options.indentation()+"looper = "+self.looper_().dumpConfig(options)
00573         if self.subProcess_():
00574             config += options.indentation()+"subProcess = "+self.subProcess_().dumpConfig(options)
00575 
00576         config+=self._dumpConfigNamedList(self.producers_().iteritems(),
00577                                   'module',
00578                                   options)
00579         config+=self._dumpConfigNamedList(self.filters_().iteritems(),
00580                                   'module',
00581                                   options)
00582         config+=self._dumpConfigNamedList(self.analyzers_().iteritems(),
00583                                   'module',
00584                                   options)
00585         config+=self._dumpConfigNamedList(self.outputModules_().iteritems(),
00586                                   'module',
00587                                   options)
00588         config+=self._dumpConfigNamedList(self.sequences_().iteritems(),
00589                                   'sequence',
00590                                   options)
00591         config+=self._dumpConfigNamedList(self.paths_().iteritems(),
00592                                   'path',
00593                                   options)
00594         config+=self._dumpConfigNamedList(self.endpaths_().iteritems(),
00595                                   'endpath',
00596                                   options)
00597         config+=self._dumpConfigUnnamedList(self.services_().iteritems(),
00598                                   'service',
00599                                   options)
00600         config+=self._dumpConfigNamedList(self.aliases_().iteritems(),
00601                                   'alias',
00602                                   options)
00603         config+=self._dumpConfigOptionallyNamedList(
00604             self.es_producers_().iteritems(),
00605             'es_module',
00606             options)
00607         config+=self._dumpConfigOptionallyNamedList(
00608             self.es_sources_().iteritems(),
00609             'es_source',
00610             options)
00611         config += self._dumpConfigESPrefers(options)
00612         for name,item in self.psets.iteritems():
00613             config +=options.indentation()+item.configTypeName()+' '+name+' = '+item.configValue(options)
00614         for name,item in self.vpsets.iteritems():
00615             config +=options.indentation()+'VPSet '+name+' = '+item.configValue(options)
00616         if self.schedule:
00617             pathNames = [p.label_() for p in self.schedule]
00618             config +=options.indentation()+'schedule = {'+','.join(pathNames)+'}\n'
00619 
00620 #        config+=self._dumpConfigNamedList(self.vpsets.iteritems(),
00621 #                                  'VPSet',
00622 #                                  options)
00623         config += "}\n"
00624         options.unindent()
00625         return config
00626     def _dumpConfigESPrefers(self, options):
00627         result = ''
00628         for item in self.es_prefers_().itervalues():
00629             result +=options.indentation()+'es_prefer '+item.targetLabel_()+' = '+item.dumpConfig(options)
00630         return result
00631     def _dumpPythonList(self, d, options):
00632         returnValue = ''
00633         if isinstance(d, DictTypes.SortedKeysDict):
00634             for name,item in d.items():
00635                 returnValue +='process.'+name+' = '+item.dumpPython(options)+'\n\n'
00636         else:
00637             for name,item in sorted(d.items()):
00638                 returnValue +='process.'+name+' = '+item.dumpPython(options)+'\n\n'
00639         return returnValue
00640     def _validateSequence(self, sequence, label):
00641         # See if every module has been inserted into the process
00642         try:
00643             l = set()
00644             nameVisitor = NodeNameVisitor(l)
00645             sequence.visit(nameVisitor)
00646         except:
00647             raise RuntimeError("An entry in sequence "+label + ' has no label')
00648     def _sequencesInDependencyOrder(self):
00649         #for each sequence, see what other sequences it depends upon
00650         returnValue=DictTypes.SortedKeysDict()
00651         dependencies = {}
00652         for label,seq in self.sequences.iteritems():
00653             d = []
00654             v = SequenceVisitor(d)
00655             seq.visit(v)
00656             dependencies[label]=[dep.label_() for dep in d if dep.hasLabel_()]
00657         resolvedDependencies=True
00658         #keep looping until we can no longer get rid of all dependencies
00659         # if that happens it means we have circular dependencies
00660         iterCount = 0
00661         while resolvedDependencies:
00662             iterCount += 1
00663             resolvedDependencies = (0 != len(dependencies))
00664             oldDeps = dict(dependencies)
00665             for label,deps in oldDeps.iteritems():
00666                 # don't try too hard
00667                 if len(deps)==0 or iterCount > 100:
00668                     iterCount = 0
00669                     resolvedDependencies=True
00670                     returnValue[label]=self.sequences[label]
00671                     #remove this as a dependency for all other sequences
00672                     del dependencies[label]
00673                     for lb2,deps2 in dependencies.iteritems():
00674                         while deps2.count(label):
00675                             deps2.remove(label)
00676         if len(dependencies):
00677             raise RuntimeError("circular sequence dependency discovered \n"+
00678                                ",".join([label for label,junk in dependencies.iteritems()]))
00679         return returnValue
00680     def _dumpPython(self, d, options):
00681         result = ''
00682         for name, value in d.iteritems():
00683            result += value.dumpPythonAs(name,options)+'\n'
00684         return result
00685     def dumpPython(self, options=PrintOptions()):
00686         """return a string containing the equivalent process defined using python"""
00687         result = "import FWCore.ParameterSet.Config as cms\n\n"
00688         result += "process = cms.Process(\""+self.__name+"\")\n\n"
00689         if self.source_():
00690             result += "process.source = "+self.source_().dumpPython(options)
00691         if self.looper_():
00692             result += "process.looper = "+self.looper_().dumpPython()
00693         if self.subProcess_():
00694             result += self.subProcess_().dumpPython(options)
00695         result+=self._dumpPythonList(self.producers_(), options)
00696         result+=self._dumpPythonList(self.filters_() , options)
00697         result+=self._dumpPythonList(self.analyzers_(), options)
00698         result+=self._dumpPythonList(self.outputModules_(), options)
00699         result+=self._dumpPythonList(self._sequencesInDependencyOrder(), options)
00700         result+=self._dumpPythonList(self.paths_(), options)
00701         result+=self._dumpPythonList(self.endpaths_(), options)
00702         result+=self._dumpPythonList(self.services_(), options)
00703         result+=self._dumpPythonList(self.es_producers_(), options)
00704         result+=self._dumpPythonList(self.es_sources_(), options)
00705         result+=self._dumpPython(self.es_prefers_(), options)
00706         result+=self._dumpPythonList(self.aliases_(), options)
00707         result+=self._dumpPythonList(self.psets, options)
00708         result+=self._dumpPythonList(self.vpsets, options)
00709         if self.schedule:
00710             pathNames = ['process.'+p.label_() for p in self.schedule]
00711             result +='process.schedule = cms.Schedule(*[ ' + ', '.join(pathNames) + ' ])\n'
00712 
00713         return result
00714     def _replaceInSequences(self, label, new):
00715         old = getattr(self,label)
00716         #TODO - replace by iterator concatenation
00717         for sequenceable in self.sequences.itervalues():
00718             sequenceable.replace(old,new)
00719         for sequenceable in self.paths.itervalues():
00720             sequenceable.replace(old,new)
00721         for sequenceable in self.endpaths.itervalues():
00722             sequenceable.replace(old,new)
00723     def globalReplace(self,label,new):
00724         """ Replace the item with label 'label' by object 'new' in the process and all sequences/paths"""
00725         if not hasattr(self,label):
00726             raise LookupError("process has no item of label "+label)
00727         self._replaceInSequences(label, new)
00728         setattr(self,label,new)
00729     def _insertInto(self, parameterSet, itemDict):
00730         for name,value in itemDict.iteritems():
00731             value.insertInto(parameterSet, name)
00732     def _insertOneInto(self, parameterSet, label, item, tracked):
00733         vitems = []
00734         if not item == None:
00735             newlabel = item.nameInProcessDesc_(label)
00736             vitems = [newlabel]
00737             item.insertInto(parameterSet, newlabel)
00738         parameterSet.addVString(tracked, label, vitems)
00739     def _insertManyInto(self, parameterSet, label, itemDict, tracked):
00740         l = []
00741         for name,value in itemDict.iteritems():
00742           newLabel = value.nameInProcessDesc_(name)
00743           l.append(newLabel)
00744           value.insertInto(parameterSet, name)
00745         # alphabetical order is easier to compare with old language
00746         l.sort()
00747         parameterSet.addVString(tracked, label, l)
00748     def _insertPaths(self, processPSet):
00749         scheduledPaths = []
00750         triggerPaths = []
00751         endpaths = []
00752         if self.schedule_() == None:
00753             # make one from triggerpaths & endpaths
00754             for name,value in self.paths_().iteritems():
00755                 scheduledPaths.append(name)
00756                 triggerPaths.append(name)
00757             for name,value in self.endpaths_().iteritems():
00758                 scheduledPaths.append(name)
00759                 endpaths.append(name)
00760         else:
00761             for path in self.schedule_():
00762                pathname = path.label_()
00763                scheduledPaths.append(pathname)
00764                if self.endpaths_().has_key(pathname):
00765                    endpaths.append(pathname)
00766                else:
00767                    triggerPaths.append(pathname)
00768         processPSet.addVString(True, "@end_paths", endpaths)
00769         processPSet.addVString(True, "@paths", scheduledPaths)
00770         # trigger_paths are a little different
00771         p = processPSet.newPSet()
00772         p.addVString(True, "@trigger_paths", triggerPaths)
00773         processPSet.addPSet(True, "@trigger_paths", p)
00774         # add all these paths
00775         pathValidator = PathValidator()
00776         endpathValidator = EndPathValidator()
00777         for triggername in triggerPaths:
00778             #self.paths_()[triggername].insertInto(processPSet, triggername, self.sequences_())
00779             pathValidator.setLabel(triggername)
00780             self.paths_()[triggername].visit(pathValidator)
00781             self.paths_()[triggername].insertInto(processPSet, triggername, self.__dict__)
00782         for endpathname in endpaths:
00783             #self.endpaths_()[endpathname].insertInto(processPSet, endpathname, self.sequences_())
00784             endpathValidator.setLabel(endpathname)
00785             self.endpaths_()[endpathname].visit(endpathValidator)
00786             self.endpaths_()[endpathname].insertInto(processPSet, endpathname, self.__dict__)
00787         processPSet.addVString(False, "@filters_on_endpaths", endpathValidator.filtersOnEndpaths)
00788 
00789     def prune(self,verbose=False):
00790         """ Remove clutter from the process which we think is unnecessary:
00791         tracked PSets, VPSets and unused modules and sequences. If a Schedule has been set, then Paths and EndPaths
00792         not in the schedule will also be removed, along with an modules and sequences used only by
00793         those removed Paths and EndPaths."""
00794         for name in self.psets_():
00795             if getattr(self,name).isTracked():
00796                 delattr(self, name)
00797         for name in self.vpsets_():
00798             delattr(self, name)
00799         #first we need to resolve any SequencePlaceholders being used
00800         for x in self.paths.itervalues():
00801             x.resolve(self.__dict__)
00802         for x in self.endpaths.itervalues():
00803             x.resolve(self.__dict__)
00804         usedModules = set()
00805         unneededPaths = set()
00806         if self.schedule_():
00807             usedModules=set(self.schedule_().moduleNames())
00808             #get rid of unused paths
00809             schedNames = set(( x.label_() for x in self.schedule_()))
00810             names = set(self.paths)
00811             names.update(set(self.endpaths))
00812             unneededPaths = names - schedNames
00813             for n in unneededPaths:
00814                 delattr(self,n)
00815         else:
00816             pths = list(self.paths.itervalues())
00817             pths.extend(self.endpaths.itervalues())
00818             temp = Schedule(*pths)
00819             usedModules=set(temp.moduleNames())
00820         unneededModules = self._pruneModules(self.producers_(), usedModules)
00821         unneededModules.update(self._pruneModules(self.filters_(), usedModules))
00822         unneededModules.update(self._pruneModules(self.analyzers_(), usedModules))
00823         #remove sequences that do not appear in remaining paths and endpaths
00824         seqs = list()
00825         sv = SequenceVisitor(seqs)
00826         for p in self.paths.itervalues():
00827             p.visit(sv)
00828         for p in self.endpaths.itervalues():
00829             p.visit(sv)
00830         keepSeqSet = set(( s for s in seqs if s.hasLabel_()))
00831         availableSeqs = set(self.sequences.itervalues())
00832         unneededSeqs = availableSeqs-keepSeqSet
00833         unneededSeqLabels = []
00834         for s in unneededSeqs:
00835             unneededSeqLabels.append(s.label_())
00836             delattr(self,s.label_())
00837         if verbose:
00838             print "prune removed the following:"
00839             print "  modules:"+",".join(unneededModules)
00840             print "  sequences:"+",".join(unneededSeqLabels)
00841             print "  paths/endpaths:"+",".join(unneededPaths)
00842     def _pruneModules(self, d, scheduledNames):
00843         moduleNames = set(d.keys())
00844         junk = moduleNames - scheduledNames
00845         for name in junk:
00846             delattr(self, name)
00847         return junk
00848 
00849     def fillProcessDesc(self, processPSet):
00850         """Used by the framework to convert python to C++ objects"""
00851         class ServiceInjectorAdaptor(object):
00852             def __init__(self,ppset,thelist):
00853                 self.__thelist = thelist
00854                 self.__processPSet = ppset
00855             def addService(self,pset):
00856                 self.__thelist.append(pset)
00857             def newPSet(self):
00858                 return self.__processPSet.newPSet()
00859         self.validate()
00860         processPSet.addString(True, "@process_name", self.name_())
00861         all_modules = self.producers_().copy()
00862         all_modules.update(self.filters_())
00863         all_modules.update(self.analyzers_())
00864         all_modules.update(self.outputModules_())
00865         self._insertInto(processPSet, self.psets_())
00866         self._insertInto(processPSet, self.vpsets_())
00867         self._insertManyInto(processPSet, "@all_modules", all_modules, True)
00868         self._insertOneInto(processPSet,  "@all_sources", self.source_(), True)
00869         self._insertOneInto(processPSet,  "@all_loopers", self.looper_(), True)
00870         self._insertOneInto(processPSet,  "@all_subprocesses", self.subProcess_(), False)
00871         self._insertManyInto(processPSet, "@all_esmodules", self.es_producers_(), True)
00872         self._insertManyInto(processPSet, "@all_essources", self.es_sources_(), True)
00873         self._insertManyInto(processPSet, "@all_esprefers", self.es_prefers_(), True)
00874         self._insertManyInto(processPSet, "@all_aliases", self.aliases_(), True)
00875         self._insertPaths(processPSet)
00876         #handle services differently
00877         services = []
00878         for n in self.services_():
00879              getattr(self,n).insertInto(ServiceInjectorAdaptor(processPSet,services))
00880         processPSet.addVPSet(False,"services",services)
00881         return processPSet
00882 
00883     def validate(self):
00884         # check if there's some input
00885         # Breaks too many unit tests for now
00886         #if self.source_() == None and self.looper_() == None:
00887         #    raise RuntimeError("No input source was found for this process")
00888         pass
00889 
00890     def prefer(self, esmodule,*args,**kargs):
00891         """Prefer this ES source or producer.  The argument can
00892            either be an object label, e.g.,
00893              process.prefer(process.juicerProducer) (not supported yet)
00894            or a name of an ESSource or ESProducer
00895              process.prefer("juicer")
00896            or a type of unnamed ESSource or ESProducer
00897              process.prefer("JuicerProducer")
00898            In addition, you can pass as a labelled arguments the name of the Record you wish to
00899            prefer where the type passed is a cms.vstring and that vstring can contain the
00900            name of the C++ types in the Record which are being preferred, e.g.,
00901               #prefer all data in record 'OrangeRecord' from 'juicer'
00902               process.prefer("juicer", OrangeRecord=cms.vstring())
00903            or
00904               #prefer only "Orange" data in "OrangeRecord" from "juicer"
00905               process.prefer("juicer", OrangeRecord=cms.vstring("Orange"))
00906            or
00907               #prefer only "Orange" data with label "ExtraPulp" in "OrangeRecord" from "juicer"
00908               ESPrefer("ESJuicerProd", OrangeRecord=cms.vstring("Orange/ExtraPulp"))
00909         """
00910         # see if this refers to a named ESProducer
00911         if isinstance(esmodule, ESSource) or isinstance(esmodule, ESProducer):
00912             raise RuntimeError("Syntax of process.prefer(process.esmodule) not supported yet")
00913         elif self._findPreferred(esmodule, self.es_producers_(),*args,**kargs) or \
00914                 self._findPreferred(esmodule, self.es_sources_(),*args,**kargs):
00915             pass
00916         else:
00917             raise RuntimeError("Cannot resolve prefer for "+repr(esmodule))
00918 
00919     def _findPreferred(self, esname, d,*args,**kargs):
00920         # is esname a name in the dictionary?
00921         if esname in d:
00922             typ = d[esname].type_()
00923             if typ == esname:
00924                 self.__setattr__( esname+"_prefer", ESPrefer(typ,*args,**kargs) )
00925             else:
00926                 self.__setattr__( esname+"_prefer", ESPrefer(typ, esname,*args,**kargs) )
00927             return True
00928         else:
00929             # maybe it's an unnamed ESModule?
00930             found = False
00931             for name, value in d.iteritems():
00932                if value.type_() == esname:
00933                   if found:
00934                       raise RuntimeError("More than one ES module for "+esname)
00935                   found = True
00936                   self.__setattr__(esname+"_prefer",  ESPrefer(d[esname].type_()) )
00937             return found
00938 
00939 class FilteredStream(dict):
00940     """a dictionary with fixed keys"""
00941     def _blocked_attribute(obj):
00942         raise AttributeError, "An FilteredStream defintion cannot be modified after creation."
00943     _blocked_attribute = property(_blocked_attribute)
00944     __setattr__ = __delitem__ = __setitem__ = clear = _blocked_attribute
00945     pop = popitem = setdefault = update = _blocked_attribute
00946     def __new__(cls, *args, **kw):
00947         new = dict.__new__(cls)
00948         dict.__init__(new, *args, **kw)
00949         keys = kw.keys()
00950         keys.sort()
00951         if keys != ['content', 'dataTier', 'name', 'paths', 'responsible', 'selectEvents']:
00952            raise ValueError("The needed parameters are: content, dataTier, name, paths, responsible, selectEvents")
00953         if not isinstance(kw['name'],str):
00954            raise ValueError("name must be of type string")
00955         if not isinstance(kw['content'], vstring) and not isinstance(kw['content'],str):
00956            raise ValueError("content must be of type vstring or string")
00957         if not isinstance(kw['dataTier'], string):
00958            raise ValueError("dataTier must be of type string")
00959         if not isinstance(kw['selectEvents'], PSet):
00960            raise ValueError("selectEvents must be of type PSet")
00961         if not isinstance(kw['paths'],(tuple, Path)):
00962            raise ValueError("'paths' must be a tuple of paths")
00963         return new
00964     def __init__(self, *args, **kw):
00965         pass
00966     def __repr__(self):
00967         return "FilteredStream object: %s" %self["name"]
00968     def __getattr__(self,attr):
00969         return self[attr]
00970 
00971 class SubProcess(_ConfigureComponent,_Unlabelable):
00972    """Allows embedding another process within a parent process. This allows one to 
00973    chain processes together directly in one cmsRun job rather than having to run
00974    separate jobs which are connected via a temporary file.
00975    """
00976    def __init__(self,process, SelectEvents = untracked.PSet(), outputCommands = untracked.vstring()):
00977       """
00978       """
00979       if not isinstance(process, Process):
00980          raise ValueError("the 'process' argument must be of type cms.Process")
00981       if not isinstance(SelectEvents,PSet):
00982          raise ValueError("the 'SelectEvents' argument must be of type cms.untracked.PSet")
00983       if not isinstance(outputCommands,vstring):
00984          raise ValueError("the 'outputCommands' argument must be of type cms.untracked.vstring")
00985       self.__process = process
00986       self.__SelectEvents = SelectEvents
00987       self.__outputCommands = outputCommands
00988    def dumpPython(self,options):
00989       out = "parentProcess"+str(hash(self))+" = process\n"
00990       out += self.__process.dumpPython()
00991       out += "childProcess = process\n"
00992       out += "process = parentProcess"+str(hash(self))+"\n"
00993       out += "process.subProcess = cms.SubProcess( process = childProcess, SelectEvents = "+self.__SelectEvents.dumpPython(options) +", outputCommands = "+self.__outputCommands.dumpPython(options) +")\n"
00994       return out
00995    def type_(self):
00996       return 'subProcess'
00997    def nameInProcessDesc_(self,label):
00998       return '@sub_process'
00999    def _place(self,label,process):
01000       process._placeSubProcess('subProcess',self)
01001    def insertInto(self,parameterSet, newlabel):
01002       topPSet = parameterSet.newPSet()
01003       self.__process.fillProcessDesc(topPSet)
01004       subProcessPSet = parameterSet.newPSet()
01005       self.__SelectEvents.insertInto(subProcessPSet,"SelectEvents")
01006       self.__outputCommands.insertInto(subProcessPSet,"outputCommands")
01007       subProcessPSet.addPSet(False,"process",topPSet)
01008       parameterSet.addPSet(False,self.nameInProcessDesc_("subProcess"), subProcessPSet)
01009 
01010 if __name__=="__main__":
01011     import unittest
01012     import copy
01013     
01014     class TestMakePSet(object):
01015         """Has same interface as the C++ object which creates PSets
01016         """
01017         def __init__(self):
01018             self.values = dict()
01019         def __insertValue(self,tracked,label,value):
01020             self.values[label]=(tracked,value)
01021         def addInt32(self,tracked,label,value):
01022             self.__insertValue(tracked,label,value)
01023         def addVInt32(self,tracked,label,value):
01024             self.__insertValue(tracked,label,value)
01025         def addUInt32(self,tracked,label,value):
01026             self.__insertValue(tracked,label,value)
01027         def addVUInt32(self,tracked,label,value):
01028             self.__insertValue(tracked,label,value)
01029         def addInt64(self,tracked,label,value):
01030             self.__insertValue(tracked,label,value)
01031         def addVInt64(self,tracked,label,value):
01032             self.__insertValue(tracked,label,value)
01033         def addUInt64(self,tracked,label,value):
01034             self.__insertValue(tracked,label,value)
01035         def addVUInt64(self,tracked,label,value):
01036             self.__insertValue(tracked,label,value)
01037         def addDouble(self,tracked,label,value):
01038             self.__insertValue(tracked,label,value)
01039         def addVDouble(self,tracked,label,value):
01040             self.__insertValue(tracked,label,value)
01041         def addBool(self,tracked,label,value):
01042             self.__insertValue(tracked,label,value)
01043         def addString(self,tracked,label,value):
01044             self.__insertValue(tracked,label,value)
01045         def addVString(self,tracked,label,value):
01046             self.__insertValue(tracked,label,value)
01047         def addInputTag(self,tracked,label,value):
01048             self.__insertValue(tracked,label,value)
01049         def addVInputTag(self,tracked,label,value):
01050             self.__insertValue(tracked,label,value)
01051         def addESInputTag(self,tracked,label,value):
01052             self.__insertValue(tracked,label,value)
01053         def addVESInputTag(self,tracked,label,value):
01054             self.__insertValue(tracked,label,value)
01055         def addEventID(self,tracked,label,value):
01056             self.__insertValue(tracked,label,value)
01057         def addVEventID(self,tracked,label,value):
01058             self.__insertValue(tracked,label,value)
01059         def addLuminosityBlockID(self,tracked,label,value):
01060             self.__insertValue(tracked,label,value)
01061         def addLuminosityBlockID(self,tracked,label,value):
01062             self.__insertValue(tracked,label,value)
01063         def addEventRange(self,tracked,label,value):
01064             self.__insertValue(tracked,label,value)
01065         def addVEventRange(self,tracked,label,value):
01066             self.__insertValue(tracked,label,value)
01067         def addPSet(self,tracked,label,value):
01068             self.__insertValue(tracked,label,value)
01069         def addVPSet(self,tracked,label,value):
01070             self.__insertValue(tracked,label,value)
01071         def addFileInPath(self,tracked,label,value):
01072             self.__insertValue(tracked,label,value)
01073         def newPSet(self):
01074             return TestMakePSet()
01075         
01076     class TestModuleCommand(unittest.TestCase):
01077         def setUp(self):
01078             """Nothing to do """
01079             None
01080         def testParameterizable(self):
01081             p = _Parameterizable()
01082             self.assertEqual(len(p.parameterNames_()),0)
01083             p.a = int32(1)
01084             self.assert_('a' in p.parameterNames_())
01085             self.assertEqual(p.a.value(), 1)
01086             p.a = 10
01087             self.assertEqual(p.a.value(), 10)
01088             p.a = untracked(int32(1))
01089             self.assertEqual(p.a.value(), 1)
01090             self.failIf(p.a.isTracked())
01091             p.a = untracked.int32(1)
01092             self.assertEqual(p.a.value(), 1)
01093             self.failIf(p.a.isTracked())
01094             p = _Parameterizable(foo=int32(10), bar = untracked(double(1.0)))
01095             self.assertEqual(p.foo.value(), 10)
01096             self.assertEqual(p.bar.value(),1.0)
01097             self.failIf(p.bar.isTracked())
01098             self.assertRaises(TypeError,setattr,(p,'c',1))
01099             p = _Parameterizable(a=PSet(foo=int32(10), bar = untracked(double(1.0))))
01100             self.assertEqual(p.a.foo.value(),10)
01101             self.assertEqual(p.a.bar.value(),1.0)
01102             p.b = untracked(PSet(fii = int32(1)))
01103             self.assertEqual(p.b.fii.value(),1)
01104             self.failIf(p.b.isTracked())
01105             #test the fact that values can be shared
01106             v = int32(10)
01107             p=_Parameterizable(a=v)
01108             v.setValue(11)
01109             self.assertEqual(p.a.value(),11)
01110             p.a = 12
01111             self.assertEqual(p.a.value(),12)
01112             self.assertEqual(v.value(),12)
01113         def testTypedParameterizable(self):
01114             p = _TypedParameterizable("blah", b=int32(1))
01115             #see if copy works deeply
01116             other = p.copy()
01117             other.b = 2
01118             self.assertNotEqual(p.b,other.b)
01119 
01120         def testProcessInsertion(self):
01121             p = Process("test")
01122             p.a = EDAnalyzer("MyAnalyzer")
01123             self.assert_( 'a' in p.analyzers_() )
01124             self.assert_( 'a' in p.analyzers)
01125             p.add_(Service("MessageLogger"))
01126             self.assert_('MessageLogger' in p.services_())
01127             self.assertEqual(p.MessageLogger.type_(), "MessageLogger")
01128             p.Tracer = Service("Tracer")
01129             self.assert_('Tracer' in p.services_())
01130             self.assertRaises(TypeError, setattr, *(p,'b',"this should fail"))
01131             self.assertRaises(TypeError, setattr, *(p,'bad',Service("MessageLogger")))
01132             self.assertRaises(ValueError, setattr, *(p,'bad',Source("PoolSource")))
01133             p.out = OutputModule("Outer")
01134             self.assertEqual(p.out.type_(), 'Outer')
01135             self.assert_( 'out' in p.outputModules_() )
01136 
01137             p.geom = ESSource("GeomProd")
01138             self.assert_('geom' in p.es_sources_())
01139             p.add_(ESSource("ConfigDB"))
01140             self.assert_('ConfigDB' in p.es_sources_())
01141 
01142             p.aliasfoo1 = EDAlias(foo1 = VPSet(PSet(type = string("Foo1"))))
01143             self.assert_('aliasfoo1' in p.aliases_())
01144 
01145         def testProcessExtend(self):
01146             class FromArg(object):
01147                 def __init__(self,*arg,**args):
01148                     for name in args.iterkeys():
01149                         self.__dict__[name]=args[name]
01150 
01151             a=EDAnalyzer("MyAnalyzer")
01152             t=EDAnalyzer("MyAnalyzer")
01153             t.setLabel("foo")
01154             s1 = Sequence(a)
01155             s2 = Sequence(s1)
01156             s3 = Sequence(s2)
01157             d = FromArg(
01158                     a=a,
01159                     b=Service("Full"),
01160                     c=Path(a),
01161                     d=s2,
01162                     e=s1,
01163                     f=s3,
01164                     g=Sequence(s1+s2+s3)
01165                 )
01166             p = Process("Test")
01167             p.extend(d)
01168             self.assertEqual(p.a.type_(),"MyAnalyzer")
01169             self.assertEqual(p.a.label_(),"a")
01170             self.assertRaises(AttributeError,getattr,p,'b')
01171             self.assertEqual(p.Full.type_(),"Full")
01172             self.assertEqual(str(p.c),'a')
01173             self.assertEqual(str(p.d),'a')
01174 
01175             z1 = FromArg(
01176                     a=a,
01177                     b=Service("Full"),
01178                     c=Path(a),
01179                     d=s2,
01180                     e=s1,
01181                     f=s3,
01182                     s4=s3,
01183                     g=Sequence(s1+s2+s3)
01184                  )
01185             
01186             p1 = Process("Test")
01187             #p1.extend(z1)
01188             self.assertRaises(ValueError, p1.extend, z1)
01189 
01190             z2 = FromArg(
01191                     a=a,
01192                     b=Service("Full"),
01193                     c=Path(a),
01194                     d=s2,
01195                     e=s1,
01196                     f=s3,
01197                     aaa=copy.deepcopy(a),
01198                     s4=copy.deepcopy(s3),
01199                     g=Sequence(s1+s2+s3),
01200                     t=t
01201                 )
01202             p2 = Process("Test")
01203             p2.extend(z2)
01204             #self.assertRaises(ValueError, p2.extend, z2)
01205             self.assertEqual(p2.s4.label_(),"s4")
01206             #p2.s4.setLabel("foo")
01207             self.assertRaises(ValueError, p2.s4.setLabel, "foo")
01208             p2.s4.setLabel("s4")
01209             p2.s4.setLabel(None)
01210             p2.s4.setLabel("foo")
01211             p2._Process__setObjectLabel(p2.s4, "foo")
01212             p2._Process__setObjectLabel(p2.s4, None)
01213             p2._Process__setObjectLabel(p2.s4, "bar")
01214 
01215         def testProcessDumpPython(self):
01216             p = Process("test")
01217             p.a = EDAnalyzer("MyAnalyzer")
01218             p.p = Path(p.a)
01219             p.s = Sequence(p.a)
01220             p.r = Sequence(p.s)
01221             p.p2 = Path(p.s)
01222             p.schedule = Schedule(p.p2,p.p)
01223             d=p.dumpPython()
01224             self.assertEqual(d,
01225 """import FWCore.ParameterSet.Config as cms
01226 
01227 process = cms.Process("test")
01228 
01229 process.a = cms.EDAnalyzer("MyAnalyzer")
01230 
01231 
01232 process.s = cms.Sequence(process.a)
01233 
01234 
01235 process.r = cms.Sequence(process.s)
01236 
01237 
01238 process.p = cms.Path(process.a)
01239 
01240 
01241 process.p2 = cms.Path(process.s)
01242 
01243 
01244 process.schedule = cms.Schedule(*[ process.p2, process.p ])
01245 """)
01246             #Reverse order of 'r' and 's'
01247             p = Process("test")
01248             p.a = EDAnalyzer("MyAnalyzer")
01249             p.p = Path(p.a)
01250             p.r = Sequence(p.a)
01251             p.s = Sequence(p.r)
01252             p.p2 = Path(p.r)
01253             p.schedule = Schedule(p.p2,p.p)
01254             p.b = EDAnalyzer("YourAnalyzer")
01255             d=p.dumpPython()
01256             self.assertEqual(d,
01257 """import FWCore.ParameterSet.Config as cms
01258 
01259 process = cms.Process("test")
01260 
01261 process.a = cms.EDAnalyzer("MyAnalyzer")
01262 
01263 
01264 process.b = cms.EDAnalyzer("YourAnalyzer")
01265 
01266 
01267 process.r = cms.Sequence(process.a)
01268 
01269 
01270 process.s = cms.Sequence(process.r)
01271 
01272 
01273 process.p = cms.Path(process.a)
01274 
01275 
01276 process.p2 = cms.Path(process.r)
01277 
01278 
01279 process.schedule = cms.Schedule(*[ process.p2, process.p ])
01280 """)
01281         #use an anonymous sequence
01282             p = Process("test")
01283             p.a = EDAnalyzer("MyAnalyzer")
01284             p.p = Path(p.a)
01285             s = Sequence(p.a)
01286             p.r = Sequence(s)
01287             p.p2 = Path(p.r)
01288             p.schedule = Schedule(p.p2,p.p)
01289             d=p.dumpPython()
01290             self.assertEqual(d,
01291             """import FWCore.ParameterSet.Config as cms
01292 
01293 process = cms.Process("test")
01294 
01295 process.a = cms.EDAnalyzer("MyAnalyzer")
01296 
01297 
01298 process.r = cms.Sequence((process.a))
01299 
01300 
01301 process.p = cms.Path(process.a)
01302 
01303 
01304 process.p2 = cms.Path(process.r)
01305 
01306 
01307 process.schedule = cms.Schedule(*[ process.p2, process.p ])
01308 """)
01309 
01310         def testSecSource(self):
01311             p = Process('test')
01312             p.a = SecSource("MySecSource")
01313             self.assertEqual(p.dumpPython().replace('\n',''),'import FWCore.ParameterSet.Config as cmsprocess = cms.Process("test")process.a = cms.SecSource("MySecSource")')
01314 
01315         def testGlobalReplace(self):
01316             p = Process('test')
01317             p.a = EDAnalyzer("MyAnalyzer")
01318             p.b = EDAnalyzer("YourAnalyzer")
01319             p.c = EDAnalyzer("OurAnalyzer")
01320             p.s = Sequence(p.a*p.b)
01321             p.p = Path(p.c+p.s+p.a)
01322             new = EDAnalyzer("NewAnalyzer")
01323             p.globalReplace("a",new)
01324 
01325         def testSequence(self):
01326             p = Process('test')
01327             p.a = EDAnalyzer("MyAnalyzer")
01328             p.b = EDAnalyzer("YourAnalyzer")
01329             p.c = EDAnalyzer("OurAnalyzer")
01330             p.s = Sequence(p.a*p.b)
01331             self.assertEqual(str(p.s),'a+b')
01332             self.assertEqual(p.s.label_(),'s')
01333             path = Path(p.c+p.s)
01334             self.assertEqual(str(path),'c+a+b')
01335             p._validateSequence(path, 'p1')
01336             notInProcess = EDAnalyzer('NotInProcess')
01337             p2 = Path(p.c+p.s*notInProcess)
01338             self.assertRaises(RuntimeError, p._validateSequence, p2, 'p2')
01339 
01340         def testSequence2(self):
01341             p = Process('test')
01342             p.a = EDAnalyzer("MyAnalyzer")
01343             p.b = EDAnalyzer("YourAnalyzer")
01344             p.c = EDAnalyzer("OurAnalyzer")
01345             testseq = Sequence(p.a*p.b)
01346             p.s = testseq
01347             #p.y = testseq
01348             self.assertRaises(ValueError, p.__setattr__, "y", testseq) 
01349 
01350         def testPath(self):
01351             p = Process("test")
01352             p.a = EDAnalyzer("MyAnalyzer")
01353             p.b = EDAnalyzer("YourAnalyzer")
01354             p.c = EDAnalyzer("OurAnalyzer")
01355             path = Path(p.a)
01356             path *= p.b
01357             path += p.c
01358             self.assertEqual(str(path),'a+b+c')
01359             path = Path(p.a*p.b+p.c)
01360             self.assertEqual(str(path),'a+b+c')
01361 #            path = Path(p.a)*p.b+p.c #This leads to problems with sequences
01362 #            self.assertEqual(str(path),'((a*b)+c)')
01363             path = Path(p.a+ p.b*p.c)
01364             self.assertEqual(str(path),'a+b+c')
01365             path = Path(p.a*(p.b+p.c))
01366             self.assertEqual(str(path),'a+b+c')
01367             path = Path(p.a*(p.b+~p.c))
01368             self.assertEqual(str(path),'a+b+~c')
01369             p.es = ESProducer("AnESProducer")
01370             self.assertRaises(TypeError,Path,p.es)
01371 
01372         def testCloneSequence(self):
01373             p = Process("test")
01374             a = EDAnalyzer("MyAnalyzer")
01375             p.a = a
01376             a.setLabel("a")
01377             b = EDAnalyzer("YOurAnalyzer")
01378             p.b = b
01379             b.setLabel("b")
01380             path = Path(a * b)
01381             p.path = Path(p.a*p.b)
01382             lookuptable = {id(a): p.a, id(b): p.b}
01383             #self.assertEqual(str(path),str(path._postProcessFixup(lookuptable)))
01384             #lookuptable = p._cloneToObjectDict
01385             #self.assertEqual(str(path),str(path._postProcessFixup(lookuptable)))
01386             self.assertEqual(str(path),str(p.path))
01387 
01388         def testSchedule(self):
01389             p = Process("test")
01390             p.a = EDAnalyzer("MyAnalyzer")
01391             p.b = EDAnalyzer("YourAnalyzer")
01392             p.c = EDAnalyzer("OurAnalyzer")
01393             p.d = EDAnalyzer("OurAnalyzer")
01394             p.path1 = Path(p.a)
01395             p.path2 = Path(p.b)
01396             p.path3 = Path(p.d)
01397 
01398             s = Schedule(p.path1,p.path2)
01399             self.assertEqual(s[0],p.path1)
01400             self.assertEqual(s[1],p.path2)
01401             p.schedule = s
01402             self.assert_('b' in p.schedule.moduleNames())
01403             self.assert_(hasattr(p, 'b'))
01404             self.assert_(hasattr(p, 'c'))
01405             self.assert_(hasattr(p, 'd'))
01406             self.assert_(hasattr(p, 'path1'))
01407             self.assert_(hasattr(p, 'path2'))
01408             self.assert_(hasattr(p, 'path3'))
01409             p.prune()
01410             self.assert_('b' in p.schedule.moduleNames())
01411             self.assert_(hasattr(p, 'b'))
01412             self.assert_(not hasattr(p, 'c'))
01413             self.assert_(not hasattr(p, 'd'))
01414             self.assert_(hasattr(p, 'path1'))
01415             self.assert_(hasattr(p, 'path2'))
01416             self.assert_(not hasattr(p, 'path3'))
01417 
01418             #adding a path not attached to the Process should cause an exception
01419             p = Process("test")
01420             p.a = EDAnalyzer("MyAnalyzer")
01421             path1 = Path(p.a)
01422             s = Schedule(path1)
01423             self.assertRaises(RuntimeError, lambda : p.setSchedule_(s) )
01424 
01425             #make sure anonymous sequences work
01426             p = Process("test")
01427             p.a = EDAnalyzer("MyAnalyzer")
01428             p.b = EDAnalyzer("MyOtherAnalyzer")
01429             p.c = EDProducer("MyProd")
01430             path1 = Path(p.c*Sequence(p.a+p.b))
01431             s = Schedule(path1)
01432             self.assert_('a' in s.moduleNames())
01433             self.assert_('b' in s.moduleNames())
01434             self.assert_('c' in s.moduleNames())
01435             p.path1 = path1
01436             p.schedule = s
01437             p.prune()
01438             self.assert_('a' in s.moduleNames())
01439             self.assert_('b' in s.moduleNames())
01440             self.assert_('c' in s.moduleNames())
01441 
01442         def testImplicitSchedule(self):
01443             p = Process("test")
01444             p.a = EDAnalyzer("MyAnalyzer")
01445             p.b = EDAnalyzer("YourAnalyzer")
01446             p.c = EDAnalyzer("OurAnalyzer")
01447             p.path1 = Path(p.a)
01448             p.path2 = Path(p.b)
01449             self.assert_(p.schedule is None)
01450             pths = p.paths
01451             keys = pths.keys()
01452             self.assertEqual(pths[keys[0]],p.path1)
01453             self.assertEqual(pths[keys[1]],p.path2)
01454             p.prune()
01455             self.assert_(hasattr(p, 'a'))
01456             self.assert_(hasattr(p, 'b'))
01457             self.assert_(not hasattr(p, 'c'))
01458             self.assert_(hasattr(p, 'path1'))
01459             self.assert_(hasattr(p, 'path2'))
01460 
01461 
01462             p = Process("test")
01463             p.a = EDAnalyzer("MyAnalyzer")
01464             p.b = EDAnalyzer("YourAnalyzer")
01465             p.c = EDAnalyzer("OurAnalyzer")
01466             p.path2 = Path(p.b)
01467             p.path1 = Path(p.a)
01468             self.assert_(p.schedule is None)
01469             pths = p.paths
01470             keys = pths.keys()
01471             self.assertEqual(pths[keys[1]],p.path1)
01472             self.assertEqual(pths[keys[0]],p.path2)
01473 
01474 
01475         def testUsing(self):
01476             p = Process('test')
01477             p.block = PSet(a = int32(1))
01478             p.modu = EDAnalyzer('Analyzer', p.block, b = int32(2))
01479             self.assertEqual(p.modu.a.value(),1)
01480             self.assertEqual(p.modu.b.value(),2)
01481 
01482         def testOverride(self):
01483             p = Process('test')
01484             a = EDProducer("A", a1=int32(0))
01485             self.assert_(not a.isModified())
01486             a.a1 = 1
01487             self.assert_(a.isModified())
01488             p.a = a
01489             self.assertEqual(p.a.a1.value(), 1)
01490             # try adding an unmodified module.
01491             # should accept it
01492             p.a = EDProducer("A", a1=int32(2))
01493             self.assertEqual(p.a.a1.value(), 2)
01494             # try adding a modified module.  Should throw
01495             # no longer, since the same (modified) say, geometry
01496             # could come from more than one cff
01497             b = EDProducer("A", a1=int32(3))
01498             b.a1 = 4
01499             #self.assertRaises(RuntimeError, setattr, *(p,'a',b))
01500             ps1 = PSet(a = int32(1))
01501             ps2 = PSet(a = int32(2))
01502             self.assertRaises(ValueError, EDProducer, 'C', ps1, ps2)
01503             self.assertRaises(ValueError, EDProducer, 'C', ps1, a=int32(3))
01504 
01505         def testExamples(self):
01506             p = Process("Test")
01507             p.source = Source("PoolSource",fileNames = untracked(string("file:reco.root")))
01508             p.foos = EDProducer("FooProducer")
01509             p.bars = EDProducer("BarProducer", foos=InputTag("foos"))
01510             p.out = OutputModule("PoolOutputModule",fileName=untracked(string("file:foos.root")))
01511             p.bars.foos = 'Foosball'
01512             self.assertEqual(p.bars.foos, InputTag('Foosball'))
01513             p.p = Path(p.foos*p.bars)
01514             p.e = EndPath(p.out)
01515             p.add_(Service("MessageLogger"))
01516 
01517         def testPrefers(self):
01518             p = Process("Test")
01519             p.add_(ESSource("ForceSource"))
01520             p.juicer = ESProducer("JuicerProducer")
01521             p.prefer("ForceSource")
01522             p.prefer("juicer")
01523             self.assertEqual(p.dumpConfig(),
01524 """process Test = {
01525     es_module juicer = JuicerProducer { 
01526     }
01527     es_source  = ForceSource { 
01528     }
01529     es_prefer  = ForceSource { 
01530     }
01531     es_prefer juicer = JuicerProducer { 
01532     }
01533 }
01534 """)
01535             p.prefer("juicer",fooRcd=vstring("Foo"))
01536             self.assertEqual(p.dumpConfig(),
01537 """process Test = {
01538     es_module juicer = JuicerProducer { 
01539     }
01540     es_source  = ForceSource { 
01541     }
01542     es_prefer  = ForceSource { 
01543     }
01544     es_prefer juicer = JuicerProducer { 
01545         vstring fooRcd = {
01546             'Foo'
01547         }
01548 
01549     }
01550 }
01551 """)
01552             self.assertEqual(p.dumpPython(),
01553 """import FWCore.ParameterSet.Config as cms
01554 
01555 process = cms.Process("Test")
01556 
01557 process.juicer = cms.ESProducer("JuicerProducer")
01558 
01559 
01560 process.ForceSource = cms.ESSource("ForceSource")
01561 
01562 
01563 process.prefer("ForceSource")
01564 
01565 process.prefer("juicer",
01566     fooRcd = cms.vstring('Foo')
01567 )
01568 
01569 """)
01570 
01571         def testFreeze(self):
01572             process = Process("Freeze")
01573             m = EDProducer("M", p=PSet(i = int32(1)))
01574             m.p.i = 2
01575             process.m = m
01576             # should be frozen
01577             #self.assertRaises(ValueError, setattr, m.p, 'i', 3)
01578             #self.assertRaises(ValueError, setattr, m, 'p', PSet(i=int32(1)))
01579             #self.assertRaises(ValueError, setattr, m.p, 'j', 1)
01580             #self.assertRaises(ValueError, setattr, m, 'j', 1)
01581             # But OK to change through the process
01582             process.m.p.i = 4
01583             self.assertEqual(process.m.p.i.value(), 4)
01584             process.m.p = PSet(j=int32(1))
01585             # should work to clone it, though
01586             m2 = m.clone(p = PSet(i = int32(5)), j = int32(8))
01587             m2.p.i = 6
01588             m2.j = 8
01589         def testSubProcess(self):
01590             process = Process("Parent")
01591             subProcess = Process("Child")
01592             subProcess.a = EDProducer("A")
01593             subProcess.p = Path(subProcess.a)
01594             subProcess.add_(Service("Foo"))
01595             process.add_( SubProcess(subProcess) )
01596             d = process.dumpPython()
01597             equalD ="""import FWCore.ParameterSet.Config as cms
01598 
01599 process = cms.Process("Parent")
01600 
01601 parentProcess = process
01602 import FWCore.ParameterSet.Config as cms
01603 
01604 process = cms.Process("Child")
01605 
01606 process.a = cms.EDProducer("A")
01607 
01608 
01609 process.p = cms.Path(process.a)
01610 
01611 
01612 process.Foo = cms.Service("Foo")
01613 
01614 
01615 childProcess = process
01616 process = parentProcess
01617 process.subProcess = cms.SubProcess( process = childProcess, SelectEvents = cms.untracked.PSet(
01618 
01619 ), outputCommands = cms.untracked.vstring())
01620 """
01621             equalD = equalD.replace("parentProcess","parentProcess"+str(hash(process.subProcess)))
01622             self.assertEqual(d,equalD)
01623             p = TestMakePSet()
01624             process.subProcess.insertInto(p,"dummy")
01625             self.assertEqual((True,['a']),p.values["@sub_process"][1].values["process"][1].values['@all_modules'])
01626             self.assertEqual((True,['p']),p.values["@sub_process"][1].values["process"][1].values['@paths'])
01627             self.assertEqual({'@service_type':(True,'Foo')}, p.values["@sub_process"][1].values["process"][1].values["services"][1][0].values)
01628         def testPrune(self):
01629             p = Process("test")
01630             p.a = EDAnalyzer("MyAnalyzer")
01631             p.b = EDAnalyzer("YourAnalyzer")
01632             p.c = EDAnalyzer("OurAnalyzer")
01633             p.d = EDAnalyzer("OurAnalyzer")
01634             p.s = Sequence(p.d)
01635             p.path1 = Path(p.a)
01636             p.path2 = Path(p.b)
01637             self.assert_(p.schedule is None)
01638             pths = p.paths
01639             keys = pths.keys()
01640             self.assertEqual(pths[keys[0]],p.path1)
01641             self.assertEqual(pths[keys[1]],p.path2)
01642             p.pset1 = PSet(parA = string("pset1"))
01643             p.pset2 = untracked.PSet(parA = string("pset2"))
01644             p.vpset1 = VPSet()
01645             p.vpset2 = untracked.VPSet()
01646             p.prune()
01647             self.assert_(hasattr(p, 'a'))
01648             self.assert_(hasattr(p, 'b'))
01649             self.assert_(not hasattr(p, 'c'))
01650             self.assert_(not hasattr(p, 'd'))
01651             self.assert_(not hasattr(p, 's'))
01652             self.assert_(hasattr(p, 'path1'))
01653             self.assert_(hasattr(p, 'path2'))
01654             self.assert_(not hasattr(p, 'pset1'))
01655             self.assert_(hasattr(p, 'pset2'))
01656             self.assert_(not hasattr(p, 'vpset1'))
01657             self.assert_(not hasattr(p, 'vpset2'))
01658 
01659             p = Process("test")
01660             p.a = EDAnalyzer("MyAnalyzer")
01661             p.b = EDAnalyzer("YourAnalyzer")
01662             p.c = EDAnalyzer("OurAnalyzer")
01663             p.d = EDAnalyzer("OurAnalyzer")
01664             p.e = EDAnalyzer("OurAnalyzer")
01665             p.s = Sequence(p.d)
01666             p.s2 = Sequence(p.b)
01667             p.s3 = Sequence(p.e)
01668             p.path1 = Path(p.a)
01669             p.path2 = Path(p.b)
01670             p.path3 = Path(p.b+p.s2)
01671             p.path4 = Path(p.b+p.s3)
01672             p.schedule = Schedule(p.path1,p.path2,p.path3)
01673             pths = p.paths
01674             keys = pths.keys()
01675             self.assertEqual(pths[keys[0]],p.path1)
01676             self.assertEqual(pths[keys[1]],p.path2)
01677             p.prune()
01678             self.assert_(hasattr(p, 'a'))
01679             self.assert_(hasattr(p, 'b'))
01680             self.assert_(not hasattr(p, 'c'))
01681             self.assert_(not hasattr(p, 'd'))
01682             self.assert_(not hasattr(p, 'e'))
01683             self.assert_(not hasattr(p, 's'))
01684             self.assert_(hasattr(p, 's2'))
01685             self.assert_(not hasattr(p, 's3'))
01686             self.assert_(hasattr(p, 'path1'))
01687             self.assert_(hasattr(p, 'path2'))
01688             self.assert_(hasattr(p, 'path3'))
01689             self.assert_(not hasattr(p, 'path4'))
01690             #test SequencePlaceholder
01691             p = Process("test")
01692             p.a = EDAnalyzer("MyAnalyzer")
01693             p.b = EDAnalyzer("YourAnalyzer")
01694             p.s = Sequence(SequencePlaceholder("a")+p.b)
01695             p.pth = Path(p.s)
01696             p.prune()
01697             self.assert_(hasattr(p, 'a'))
01698             self.assert_(hasattr(p, 'b'))
01699             self.assert_(hasattr(p, 's'))
01700             self.assert_(hasattr(p, 'pth'))
01701 
01702     unittest.main()