Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:03:30

0001 from __future__ import print_function
0002 #------------------------------------------------------------
0003 #
0004 #
0005 # cmsconfig: a class to provide convenient access to the Python form
0006 # of a parsed CMS configuration file.
0007 #
0008 # Note: we have not worried about security. Be careful about strings
0009 # you put into this; we use a naked 'eval'!
0010 #
0011 #------------------------------------------------------------
0012 #
0013 # Tests for this class need to be run 'by hand', until we figure out
0014 # how to make use of the SCRAMV1 tools for running tests on Python
0015 # code.
0016 #
0017 #------------------------------------------------------------
0018 # TODO: We need some refactoring to handle the writing of module-like
0019 # objects more gracefully. Right now, we have to pull the classname
0020 # out of the dictionary in more than one place. Try making a class
0021 # which represents the module, which contains the dictionary now used,
0022 # and knows about special features: the class name, now to print the
0023 # guts without repeating the classname, etc.
0024 #------------------------------------------------------------
0025 
0026 import io
0027 import types
0028 
0029 # TODO: Refactor pset_dict_to_string and class printable_parameter to
0030 # have a consistent view of the problem. Perhaps have a class
0031 # representing the configuration data for a PSet object, rather than
0032 # just using a dictionary instance. See also __write_module_guts,
0033 # which should be refactored at the same time.
0034 
0035 def pset_dict_to_string(psetDict):
0036     """Convert dictionary representing a PSet to a string consistent
0037     with the configuration grammar."""
0038     stream = io.StringIO()
0039     stream.write('\n{\n')
0040 
0041     for name, value in psetDict.items():
0042         stream.write('%s' % printable_parameter(name, value))
0043         stream.write('\n')        
0044 
0045     stream.write('}\n')
0046     return stream.getvalue()
0047 
0048 
0049 def secsource_dict_to_string(secSourceDict):
0050     """Make a string representing the secsource"""
0051     stream = io.StringIO()
0052     stream.write("%s\n{\n" %  secSourceDict["@classname"][2])
0053     for name, value in secSourceDict.items():
0054         if name[0] != '@':
0055             stream.write('%s' % printable_parameter(name, value))
0056             stream.write('\n')
0057 
0058     stream.write('}\n')
0059     return stream.getvalue()
0060 
0061 
0062 class printable_parameter:
0063     """A class to provide automatic unpacking of the tuple (triplet)
0064     representation of a single parameter, suitable for printing.
0065 
0066     Note that 'value' may in fact be a list."""
0067 
0068     def __init__(self, aName, aValueTuple):
0069         self.name = aName
0070         self.type, self.trackedCode, self.value = aValueTuple
0071         # Because the configuration grammar treats tracked status as
0072         # the default, we only have to write 'untracked' as the
0073         # tracking code if the parameter is untracked.        
0074         if self.trackedCode == "tracked":
0075             self.trackedCode = ""
0076         else:
0077             self.trackedCode = "untracked " # trailing space is needed
0078 
0079         # We need special handling of some of the parameter types.
0080         if self.type in ["vbool", "vint32", "vuint32", "vdouble", "vstring", "VInputTag", "VESInputTag"]:   
0081             # TODO: Consider using cStringIO, if this is observed
0082             # to be a bottleneck. This may happen if many large
0083             # vectors are used in parameter sets.
0084             temp = '{'
0085             # Write out values as a comma-separated list
0086             temp += ", ".join(self.value)
0087             temp += '}'
0088             self.value = temp
0089 
0090         if self.type == "PSet":
0091             self.value = pset_dict_to_string(self.value)
0092         if self.type == "secsource":
0093             self.value = secsource_dict_to_string(self.value)
0094         if self.type == "VPSet":
0095             temp = '{'
0096             tup = [ pset_dict_to_string(x) for x in self.value ]
0097             temp += ", ".join( tup )
0098             temp += '}'
0099             self.value = temp
0100 
0101     def __str__(self):
0102         """Print this parameter in the right format for a
0103         configuration file."""
0104         s = "%(trackedCode)s%(type)s %(name)s = %(value)s" % self.__dict__
0105         return s    
0106 
0107 # I'm not using new-style classes, because I'm not sure that we can
0108 # rely on a new enough version of Python to support their use.
0109 
0110 class cmsconfig:
0111     """A class to provide convenient access to the contents of a
0112     parsed CMS configuration file."""
0113 
0114     def __init__(self, stringrep):
0115         """Create a cmsconfig object from the contents of the (Python)
0116         exchange format for configuration files."""
0117         self.psdata = eval(stringrep)
0118 
0119     def numberOfModules(self):
0120         return len(self.psdata['modules'])
0121 
0122     def numberOfOutputModules(self):
0123         return len(self.outputModuleNames())
0124 
0125     def moduleNames(self):
0126         """Return the names of modules. Returns a list."""
0127         return self.psdata['modules'].keys()
0128 
0129     def module(self, name):
0130         """Get the module with this name. Exception raised if name is
0131         not known. Returns a dictionary."""
0132         return self.psdata['modules'][name]
0133 
0134     def psetNames(self):
0135         """Return the names of psets. Returns a list."""
0136         return self.psdata['psets'].keys()
0137 
0138     def pset(self, name):
0139         """Get the pset with this name. Exception raised if name is
0140         not known. Returns a dictionary."""
0141         return self.psdata['psets'][name]
0142 
0143     def outputModuleNames(self):
0144         return self.psdata['output_modules']
0145 
0146     def moduleNamesWithSecSources(self):
0147         return self.psdata['modules_with_secsources']
0148 
0149     def esSourceNames(self):
0150         """Return the names of all ESSources. Names are of the form '<C++ type>@<label>' where
0151         label can be empty. Returns a list."""
0152         return self.psdata['es_sources'].keys()
0153 
0154     def esSource(self, name):
0155         """Get the ESSource with this name. Exception raised if name is
0156         not known. Returns a dictionary."""
0157         return self.psdata['es_sources'][name]
0158 
0159     def esModuleNames(self):
0160         """Return the names of all ESModules. Names are of the form '<C++ type>@<label>' where
0161         label can be empty. Returns a list."""
0162         return self.psdata['es_modules'].keys()
0163 
0164     def esModule(self, name):
0165         """Get the ESModule with this name. Exception raised if name is
0166         not known. Returns a dictionary."""
0167         return self.psdata['es_modules'][name]
0168 
0169     def esPreferNames(self):
0170         """Return the names of all es_prefer statements. Names are of the form 'esprefer_<C++ type>@<label>' where
0171         label can be empty. Returns a list."""
0172         return self.psdata['es_prefers'].keys()
0173 
0174     def esPrefer(self, name):
0175         """Get the es_prefer statement with this name. Exception raised if name is
0176         not known. Returns a dictionary."""
0177         return self.psdata['es_prefers'][name]
0178 
0179     def serviceNames(self):
0180         """Return the names of all Services. Names are actually the C++ class names
0181         Returns a list."""
0182         return self.psdata['services'].keys()
0183 
0184     def service(self, name):
0185         """Get the Service with this name. Exception raised if name is
0186         not known. Returns a dictionary."""
0187         return self.psdata['services'][name]
0188 
0189     def pathNames(self):
0190         return self.psdata['paths'].keys()
0191 
0192     def path(self, name):
0193         """Get the path description for the path of the given
0194         name. Exception raised if name is not known. Returns a
0195         string."""
0196         return self.psdata['paths'][name]
0197 
0198     def schedule(self):
0199         return self.psdata['schedule']
0200 
0201     def sequenceNames(self):
0202         return self.psdata['sequences'].keys()
0203 
0204     def sequence(self, name):
0205         """Get the sequence description for the sequence of the given
0206         name. Exception raised if name is not known. Returns a
0207         string."""
0208         return self.psdata['sequences'][name]
0209 
0210     def endpathNames(self):
0211         return self.psdata['endpaths'].keys()
0212 
0213     def endpath(self, name):
0214         """Return the endpath description, as a string."""
0215         return self.psdata['endpaths'][name]
0216 
0217     def mainInputSource(self):
0218         """Return the description of the main input source, as a
0219         dictionary."""
0220         return self.psdata['main_input']
0221 
0222     def looper(self):
0223         """Return the description of the looper, as a
0224         dictionary."""
0225         return self.psdata['looper']
0226 
0227     def procName(self):
0228         """Return the process name, a string"""
0229         return self.psdata['procname']
0230 
0231     def asConfigurationString(self):
0232         """Return a string conforming to the configuration file
0233         grammar, encoding this configuration."""
0234 
0235         # Let's try to make sure we lose no resources if something
0236         # fails in formatting...
0237         result = ""
0238 
0239         try:
0240             stream = io.StringIO()
0241             self.__write_self_to_stream(stream)
0242             result = stream.getvalue()
0243 
0244         finally:
0245             stream.close()
0246 
0247         return result
0248 
0249     def asPythonString(self):
0250         """Return a string containing the python psdata source of
0251         this object to facilitate saving and loading of python format"""
0252         result = "#!/usr/bin/env python\n"
0253         result += str(self.psdata)
0254         return result 
0255 
0256     def __write_self_to_stream(self, fileobj):
0257         """Private method.
0258         Return None.
0259         Write the contents of self to the file-like object fileobj."""
0260 
0261         # Write out the process block
0262         fileobj.write('process %s = \n{\n' % self.procName())
0263         self.__write_process_block_guts(fileobj)
0264         fileobj.write('}\n')
0265 
0266     def __write_process_block_guts(self, fileobj):
0267         """Private method.
0268         Return None.
0269         Write the guts of the process block to the file-like object
0270         fileobj."""
0271 
0272         # TODO: introduce, and deal with, top-level PSet objects and
0273         # top-level block objects.        
0274         self.__write_main_source(fileobj)
0275         self.__write_looper(fileobj)
0276         self.__write_psets(fileobj)
0277         self.__write_es_sources(fileobj)        
0278         self.__write_es_modules(fileobj)
0279         self.__write_es_prefers(fileobj)
0280         self.__write_modules(fileobj)
0281         self.__write_services(fileobj)
0282         self.__write_sequences(fileobj)
0283         self.__write_paths(fileobj)
0284         self.__write_endpaths(fileobj)
0285         self.__write_schedule(fileobj)
0286 
0287     def __write_psets(self, fileobj):
0288         """Private method.
0289         Return None
0290         Write all the psets to the file-like object fileobj."""
0291         for name in self.psetNames():
0292             psettuple = self.pset(name)
0293             # 8/2006: Wasn't writing trackedness!  Just re-use code
0294             # for embedded PSets
0295             fileobj.write('%s' % printable_parameter(name, psettuple))
0296             #fileobj.write("PSet %s = \n{\n" % (name) )
0297             #psetdict = psettuple[2]
0298             #self.__write_module_guts(psetdict, fileobj)
0299             #fileobj.write('}\n')
0300 
0301     def __write_modules(self, fileobj):
0302         """Private method.
0303         Return None
0304         Write all the modules to the file-like object fileobj."""
0305         for name in self.moduleNames():
0306             moddict = self.module(name)
0307             fileobj.write("module %s = %s\n{\n" % (name, moddict['@classname'][2]))
0308             self.__write_module_guts(moddict, fileobj)
0309             fileobj.write('}\n')
0310 
0311     def __write_es_sources(self, fileobj):
0312         """Private method.
0313         Return None
0314         Write all ESSources to the file-like object
0315         fileobj."""
0316         for name in self.esSourceNames():
0317             es_source_dict = self.esSource(name)
0318             fileobj.write("es_source %s = %s\n{\n" % (es_source_dict['@label'][2], es_source_dict['@classname'][2]))
0319             self.__write_module_guts(es_source_dict, fileobj)
0320             fileobj.write('}\n')
0321 
0322     def __write_es_modules(self, fileobj):
0323         """Private method.
0324         Return None
0325         Write all ESModules to the file-like object
0326         fileobj."""
0327         for name in self.esModuleNames():
0328             es_mod_dict = self.esModule(name)
0329             fileobj.write("es_module %s = %s\n{\n" % (es_mod_dict['@label'][2], es_mod_dict['@classname'][2]))
0330             self.__write_module_guts(es_mod_dict, fileobj)
0331             fileobj.write('}\n')
0332 
0333     def __write_es_prefers(self, fileobj):
0334         """Private method.
0335         Return None
0336         Write all es_prefer statements to the file-like object
0337         fileobj."""
0338         for name in self.esPreferNames():
0339             es_mod_dict = self.esPrefer(name)
0340             fileobj.write("es_prefer %s = %s\n{\n" % (es_mod_dict['@label'][2], es_mod_dict['@classname'][2]))
0341             self.__write_module_guts(es_mod_dict, fileobj)
0342             fileobj.write('}\n')
0343 
0344     def __write_services(self, fileobj):
0345         """Private method.
0346         Return None
0347         Write all Services to the file-like object
0348         fileobj."""
0349         for name in self.serviceNames():
0350             es_mod_dict = self.service(name)
0351             fileobj.write("service = %s\n{\n" % (es_mod_dict['@classname'][2]))
0352             self.__write_module_guts(es_mod_dict, fileobj)
0353             fileobj.write('}\n')
0354 
0355     def __write_sequences(self, fileobj):
0356         """Private method.
0357         Return None
0358         Write all the sequences to the file-like object fileobj."""
0359         for name in self.sequenceNames():
0360             fileobj.write("sequence %s = {%s}\n"  % (name, self.sequence(name)))
0361 
0362 
0363     def __write_paths(self, fileobj):
0364         """Private method.
0365         Return None
0366         Write all the paths to the file-like object fileobj."""
0367         for name in self.pathNames():
0368             fileobj.write("path %s = {%s}\n" % (name, self.path(name)))
0369 
0370 
0371     def __write_endpaths(self, fileobj):
0372         """Private method.
0373         Return None
0374         Write all the endpaths to the file-like object
0375         fileobj."""
0376         for name in self.endpathNames():
0377             fileobj.write("endpath %s = {%s}\n" % (name, self.endpath(name)))
0378 
0379     def __write_schedule(self, fileobj):
0380         fileobj.write("schedule = {%s}\n" % self.schedule())
0381 
0382     def __write_main_source(self, fileobj):
0383         """Private method.
0384         Return None
0385         Write the (main) source block to the file-like object
0386         fileobj."""
0387         mis = self.mainInputSource()  # this is a dictionary
0388         if mis:
0389             fileobj.write('source = %s\n{\n' % mis['@classname'][2])
0390             self.__write_module_guts(mis, fileobj)
0391             fileobj.write('}\n')
0392 
0393     def __write_looper(self, fileobj):
0394         """Private method.
0395         Return None
0396         Write the looper block to the file-like object
0397         fileobj."""
0398         mis = self.looper()  # this is a dictionary
0399         if mis:
0400             fileobj.write('looper = %s\n{\n' % mis['@classname'][2])
0401             self.__write_module_guts(mis, fileobj)
0402             fileobj.write('}\n')
0403 
0404 
0405     def __write_module_guts(self, moddict, fileobj):
0406         """Private method.
0407         Return None
0408         Print the body of the block for this 'module'. This includes
0409         all the dictionary contents except for the classname (because
0410         the classname does not appear within the block).
0411 
0412         NOTE: This should probably be a static method, because it doesn't
0413         use any member data of the object, but I'm not sure we can
0414         rely on a new-enough version of Python to make use of static
0415         methods."""
0416         for name, value in moddict.items():
0417             if name[0] != '@':
0418                 fileobj.write('%s' % printable_parameter(name, value))
0419                 fileobj.write('\n')
0420 
0421 
0422 
0423 if __name__ == "__main__":
0424     from sys import argv
0425     filename = "complete.pycfg"
0426     if len(argv) > 1:
0427         filename = argv[1]
0428 
0429     txt = file(filename).read()
0430     cfg = cmsconfig(txt)
0431     print(cfg.asConfigurationString())
0432 
0433