CMS 3D CMS Logo

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