CMS 3D CMS Logo

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