CMS 3D CMS Logo

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