CMS 3D CMS Logo

VarParsing.py

Go to the documentation of this file.
00001 import sys
00002 import os
00003 import re
00004 from FWCore.Python.Enumerate import Enumerate
00005 
00006 class VarParsing (object):
00007     """Infrastructure to parse variable definitions passed to cmsRun
00008     configuration scripts"""
00009 
00010 
00011     multiplicity = Enumerate ("singleton list", "multiplicity")
00012     varType      = Enumerate ("int float string tagString")
00013 
00014 
00015     def __init__ (self, *args):
00016         """Class initializer"""
00017         # Set everything up first
00018         self._singletons = {}
00019         self._lists      = {}
00020         self._register   = {}
00021         self._beenSet    = {}
00022         self._info       = {}
00023         self._types      = {}
00024         self._maxLength  = 0
00025         self._tags       = {}
00026         self._tagOrder   = []
00027         # now play with the rest
00028         for arg in args:
00029             if arg.lower() == "standard":
00030                 # load in standard arguments and defaults
00031                 self.register ('maxEvents',
00032                                -1,
00033                                VarParsing.multiplicity.singleton,
00034                                VarParsing.varType.int,
00035                                "Number of events to process (-1 for all)")
00036                 self.register ('files',
00037                                '',
00038                                VarParsing.multiplicity.list,
00039                                VarParsing.varType.string,
00040                                "Files to process")
00041                 self.register ('secondaryFiles',
00042                                '',
00043                                VarParsing.multiplicity.list,
00044                                VarParsing.varType.string,
00045                                "Second group of files to process (if needed)")
00046                 self.register ('output',
00047                                'output.root',
00048                                VarParsing.multiplicity.singleton,
00049                                VarParsing.varType.tagString,
00050                                "Name of output file (if needed)")
00051                 self.register ('secondaryOutput',
00052                                '',
00053                                VarParsing.multiplicity.singleton,
00054                                VarParsing.varType.tagString,
00055                                "Name of second output file (if needed)")
00056                 self.setupTags (tag = 'numEvent%d',
00057                                 ifCond = 'maxEvents > 0',
00058                                 tagArg = 'maxEvents')
00059                 continue
00060             # if we're still here, then we've got a rogue arument
00061             print "Error: VarParsing.__init__ doesn't understand '%s'" \
00062                   % arg
00063             raise RuntimeError, "Failed to create VarParsing object"
00064 
00065 
00066     def setupTags (self, **kwargs):
00067         """Sets up information for tags for output names"""
00068         necessaryKeys = set (['ifCond', 'tag'])
00069         allowedKeys   = set (['tagArg'])
00070         for key in kwargs.keys():
00071             if key in allowedKeys:
00072                 continue
00073             if key in necessaryKeys:
00074                 necessaryKeys.remove (key)
00075                 continue
00076             # if we're here, then we have a key that's not understood
00077             print "Unknown option '%s'" % key
00078             raise RuntimeError, "Unknown option"
00079         if necessaryKeys:
00080             # if this is not empty, then we didn't have a key that was
00081             # necessary.
00082             print "Missing keys: %s" % necessaryKeys
00083             raise runtimeError, "Missing keys"
00084         tag = kwargs.get('tag')
00085         del kwargs['tag']
00086         self._tags[tag] = kwargs
00087         self._tagOrder.append (tag)
00088 
00089 
00090     def parseArguments (self):
00091         """Parses command line arguments.  Parsing starts just after
00092         the name of the configuration script.  Parsing will fail if
00093         there is not 'xxxx.py'"""
00094         foundPy      = False
00095         printStatus  = False
00096         help         = False
00097         singleAssign = True 
00098         for arg in sys.argv:
00099             if not foundPy and arg.endswith ('.py'):
00100                 foundPy = True
00101                 continue
00102             if not foundPy:
00103                 continue
00104             # If we're here, then we can parse to our hearts content.
00105             # So, is this a command or a declaration?
00106             if arg.count('='):
00107                 # declaration
00108                 name, value = arg.split ('=', 1)
00109                 if name.count('_'):
00110                     # name with command
00111                     name, command = name.split ('_', 1)
00112                     command = command.lower()
00113                     if command == 'load':
00114                         self.loadFromFile (name, value)
00115                         continue
00116                     # If we're here, then I don't recognize this command
00117                     print "Unknown command '%s' in '%s_%s" % \
00118                           (command, name, command)
00119                     raise RuntimeError, "Illegal parsing command"
00120                 else:
00121                     # just a name and value
00122                     if not self._register.has_key (name):
00123                         print "Error:  '%s' not registered." \
00124                               % name
00125                         raise RuntimeError, "Unknown variable"
00126                     if VarParsing.multiplicity.singleton == \
00127                            self._register[name]:
00128                         # singleton
00129                         if self._beenSet.get (name) and singleAssign:
00130                             print "Variable '%s' assigned multiple times. Use" \
00131                                   , "'multipleAssign' command to avoid"
00132                             raise RuntimeError, "Multiple assignment"
00133                         self._beenSet[name] = True
00134                         self.setDefault (name, value)
00135                     else:
00136                         # list
00137                         self.setDefault (name, value)
00138             else:
00139                 # commands
00140                 if arg.count('_'):
00141                     # name modifier
00142                     name, command = arg.split ('_', 1)
00143                     command = command.lower()
00144                     if not self._register.has_key (name):
00145                         print "Error:  '%s' not registered." \
00146                               % name
00147                         raise RuntimeError, "Unknown variable"
00148                     if command == 'clear':
00149                         self.clearList (name)
00150                         continue
00151                     # if we're still here, complain that we don't
00152                     # understand this command:
00153                     print "Do not understand '%s' in '%s'" % (command, arg)
00154                     raise RuntimeError, "Unknown command"
00155                 else:
00156                     # simple command
00157                     command = arg.lower()
00158                     if command == 'help':
00159                         help = True
00160                     elif command == 'print':
00161                         printStatus = True
00162                     else:
00163                         # We don't understand this command
00164                         print "Do not understand command '%s'" % (arg)
00165                         raise RuntimeError, "Unknown command"
00166             # else if declaration
00167         # make sure found the py file
00168         if not foundPy:
00169             print "VarParsing.parseArguments() Failure: No configuration " + \
00170                   "file found ending in .py."
00171             raise RuntimeError, "Invalid configuration ending"
00172         if help:
00173             self.help()
00174         if printStatus:
00175             print "Printing status"
00176             print self
00177 
00178 
00179     def clearList (self, name):
00180         """Empties all entries from list"""
00181         if not self._register.has_key (name):
00182             print "Error:  '%s' not registered." \
00183                   % name
00184             raise RuntimeError, "Unknown variable"
00185         if self._register[name] == \
00186                VarParsing.multiplicity.list:
00187             self._lists[name] = []
00188         else:
00189             print "Error: '%s' is not a list" % name
00190             raise RuntimeError, "Faulty 'clear' command"
00191 
00192 
00193     def loadFromFile (self, name, filename):
00194         """Loads a list from file"""
00195         if not self._register.has_key (name):
00196             print "Error:  '%s' not registered." \
00197                   % name
00198             raise RuntimeError, "Unknown variable"
00199         if self._register[name] != VarParsing.multiplicity.list:
00200             print "Error: '%s' is not a list" % name
00201             raise RuntimeError, "'load' only works for lists"
00202         filename = os.path.expanduser (filename)
00203         if not os.path.exists (filename):
00204             print "Error: '%s' file does not exist."
00205             raise RuntimeError, "Bad filename"
00206         source = open (filename, 'r')        
00207         for line in source.readlines():
00208             line = re.sub (r'#.+$', '', line) # remove comment characters
00209             line = line.strip()
00210             if len (line):
00211                 self._lists[name].append( self._convert (name, line ) )
00212         source.close()
00213 
00214 
00215     def help (self):
00216         """Prints out help information and exits"""
00217         print self
00218         print """Options:
00219         help           : This screen
00220         multipleAssign : Allows singletons to have multiple assigments
00221         print          : Prints out current values
00222         XXX_clear      : Clears list named 'XXX'
00223         """    
00224         sys.exit (0)
00225 
00226 
00227     def register (self, name,
00228                   default = "",
00229                   mult    = multiplicity.singleton,
00230                   mytype  = varType.int,
00231                   info    = ""):
00232         """Register a variable"""
00233         # is type ok?
00234         if not VarParsing.multiplicity.isValidValue (mult):
00235             print "Error: VarParsing.register() must use ",\
00236                   "VarParsing.multiplicity."
00237             raise RuntimeError, "Improper 'mult' value"
00238         if not VarParsing.varType.isValidValue (mytype):
00239             print "Error: VarParsing.register() must use ",\
00240                   "VarParsing.varType."
00241             raise RuntimeError, "Improper 'type' value"
00242         if VarParsing.multiplicity.list == mult and \
00243            VarParsing.varType.tagString == mytype:
00244             print "Error: 'tagString' can only be used with 'singleton'"
00245             raise RuntimeError, "Improper registration"
00246         # is the name ok
00247         if name.count ("_"):
00248             print "Error: Name can not contain '_': %s" % name
00249             raise RuntimeError, "Improper 'name'"
00250         # has this been registered before?
00251         if self._register.has_key (name):
00252             # Uh oh
00253             print "Error: You can not register a name twice, '%s'" \
00254                   % name
00255             raise RuntimeError, "Attempt to re-register variable"
00256         self._register[name] = mult
00257         self._beenSet[name]  = False
00258         self._info[name]     = info
00259         self._types[name]    = mytype
00260         if len (name) > self._maxLength:
00261             self._maxLength = len (name)
00262         if VarParsing.multiplicity.singleton == mult:
00263             self._singletons[name] = default
00264         else:
00265             self._lists[name] = []
00266             # if it's a list, we only want to use the default if it
00267             # does exist.
00268             if len (default):
00269                 self._lists[name].append (default)
00270 
00271 
00272     def setType (self, name, mytype):
00273         """Change the type of 'name' to 'mytype'"""
00274         if not VarParsing.varType.isValidValue (mytype):
00275             print "Error: VarParsing.setType() must use ",\
00276                   "VarParsing.varType."
00277             raise RuntimeError, "Improper 'type' value"
00278         oldVal = self.__getattr__ (name, noTags = True)
00279         self._types[name] = mytype
00280         self.setDefault (name, oldVal)
00281         
00282 
00283     def setDefault (self, name, *args):
00284         """Used to set or change the default of an already registered
00285         name"""
00286         # has this been registered?
00287         if not self._register.has_key (name):
00288             print "Error: VarParsing.setDefault '%s' not already registered." \
00289                   % name
00290             raise RuntimeError, "setDefault without registration"
00291         if VarParsing.multiplicity.singleton == self._register[name]:
00292             # make sure we only have one value
00293             if len (args) != 1:
00294                 print "Error: VarParsing.setDefault needs exactly 1 ",\
00295                       "value for '%s'" % name
00296                 raise RuntimeError, "setDefault args problem"
00297             self._singletons[name] = self._convert (name, args[0])
00298         else:
00299             # if args is a tuple and it only has one entry, get rid of
00300             # the first level of tupleness:
00301             if isinstance (args, tuple) and len (args) == 1:
00302                 args = args[0]
00303             # is this still a tuple
00304             if isinstance (args, tuple):
00305                 mylist = list (args)
00306             else:
00307                 mylist = []
00308                 mylist.append (args)
00309             self._lists[name] = []
00310             for item in mylist:
00311                 self._lists[name].append( self._convert (name, item ) )
00312 
00313 
00314     def _convert (self, name, inputVal):
00315         """Converts inputVal to the type required by name"""
00316         inputVal = str (inputVal)
00317         if self._types[name] == VarParsing.varType.string or \
00318            self._types[name] == VarParsing.varType.tagString:
00319             return inputVal
00320         elif self._types[name] == VarParsing.varType.int:
00321             return int (inputVal, 0)
00322         elif self._types[name] == VarParsing.varType.float:
00323             return float (inputVal)
00324         else:
00325             raise RuntimeError, "Unknown varType"
00326         
00327 
00328     def _withTags (self, name):
00329         if not self._register.has_key (name):
00330             print "Error:  '%s' not registered." \
00331                   % name
00332             raise RuntimeError, "Unknown variable"
00333         if self._register[name] == VarParsing.multiplicity.list:
00334             print "Error: '%s' is a list" % name
00335             raise RuntimeError, "withTags() only works on singletons"
00336         retval = self._singletons[name]
00337         if retval.endswith ('.root'):
00338             retval, garbage = os.path.splitext (retval)
00339         reverseOrder = self._tagOrder
00340         reverseOrder.reverse()
00341         for tag in reverseOrder:
00342             tagDict = self._tags[tag]
00343             ifCond = tagDict['ifCond']
00344             if ifCond.count('%'):
00345                 pass
00346             else:
00347                 ifCond = "self." + ifCond
00348             boolValue = eval (ifCond)
00349             tagArg = tagDict.get ('tagArg')
00350             if tagArg:
00351                 evalString = "'%s' %% self.%s" % (tag, tagArg)
00352                 tag = eval (evalString)
00353             if boolValue:
00354                 retval = retval + "_" + tag        
00355         return retval + ".root"
00356             
00357 
00358     def __str__ (self):
00359         """String form of self"""
00360         maxLen = min (self._maxLength, 20)
00361         form     = "  %%-%ds: %%s" % maxLen
00362         formInfo = "  %%%ds  - %%s" % (maxLen - 2)
00363         formItem = "  %%%ds    %%s" % (maxLen - 1)
00364         retval = ""
00365         if len (self._singletons.keys()):
00366             retval = retval + "Singletons:\n"
00367         for varName, value in sorted (self._singletons.iteritems()):
00368             retval = retval + form % (varName, value) + "\n";
00369             if self._info.get(varName):
00370                 retval = retval + formInfo % ('', self._info[varName]) + "\n"
00371         if len (self._singletons.keys()):
00372             retval = retval +  "Lists:\n"
00373         for varName, value in sorted (self._lists.iteritems()):
00374             stringValue = "%s" % value
00375             if len (stringValue) < 76 - maxLen:
00376                 retval = retval + form % (varName, value) + "\n"
00377             else:
00378                 varLength = len (value)
00379                 for index, item in enumerate (value):
00380                     if index == 0:
00381                         retval = retval + form % (varName, "['" + item)
00382                     else:
00383                         retval = retval + formItem % ('',"'" + item)
00384                     if index == varLength - 1:
00385                         retval = retval + "' ]\n"
00386                     else:
00387                         retval = retval + "',\n"
00388             if self._info.get(varName):
00389                 retval = retval + formInfo % ('', self._info[varName]) + "\n"
00390         return retval
00391 
00392 
00393     def __setattr__ (self, name, value, *extras):
00394         """Lets me set internal values, or uses setDefault"""
00395         if not name.startswith ("_"):
00396             mylist = list (extras)
00397             mylist.insert (0, value)
00398             self.setDefault (name, *mylist)
00399         else:
00400             object.__setattr__ (self, name, value)
00401 
00402 
00403     def __getattr__ (self, name, noTags = False):
00404         """Lets user get the info they want with obj.name"""
00405         if name.startswith ("_"):
00406             # internal use
00407             return object.__getattribute__ (self, name)
00408         else:
00409             # user variable
00410             if not self._register.has_key (name):
00411                 print "Error:  '%s' not already registered." \
00412                       % name
00413                 raise RuntimeError, "Unknown variable"
00414             if VarParsing.multiplicity.singleton == self._register[name]:
00415                 if VarParsing.varType.tagString == self._types[name] \
00416                        and not noTags:
00417                     return self._withTags (name)
00418                 else:
00419                     return self._singletons[name]
00420             else:
00421                 return self._lists[name]
00422  
00423 
00424 ##############################################################################
00425 ## ######################################################################## ##
00426 ## ##                                                                    ## ##
00427 ## ######################################################################## ##
00428 ##############################################################################
00429 
00430     
00431 if __name__ == "__main__":
00432     #############################################
00433     ## Load and save command line history when ##
00434     ## running interactively.                  ##
00435     #############################################
00436     import os, readline
00437     import atexit
00438     historyPath = os.path.expanduser("~/.pyhistory")
00439 
00440 
00441     def save_history(historyPath=historyPath):
00442         import readline
00443         readline.write_history_file(historyPath)
00444         if os.path.exists(historyPath):
00445             readline.read_history_file(historyPath)
00446 
00447 
00448     atexit.register(save_history)
00449     readline.parse_and_bind("set show-all-if-ambiguous on")
00450     readline.parse_and_bind("tab: complete")
00451     if os.path.exists (historyPath) :
00452         readline.read_history_file(historyPath)
00453         readline.set_history_length(-1)
00454 
00455 
00456     ############################
00457     # Example code starts here #
00458     ############################
00459 
00460     obj = VarParsing ('standard')
00461     obj.register ('someVar',
00462                   mult=VarParsing.multiplicity.singleton,
00463                   info="for testing")
00464     obj.setupTags (tag    = "someCondition",
00465                    ifCond = "someVar")
00466     ## obj.register ('numbers',
00467     ##               mult=VarParsing.multiplicity.list,
00468     ##               info="Numbers")
00469     ## obj.register ('singleNumber',
00470     ##               mult=VarParsing.multiplicity.singleton,
00471     ##               info="A single number")
00472     obj.parseArguments()
00473     

Generated on Tue Jun 9 17:36:27 2009 for CMSSW by  doxygen 1.5.4