CMS 3D CMS Logo

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