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
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
00028 for arg in args:
00029 if arg.lower() == "standard":
00030
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
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
00077 print "Unknown option '%s'" % key
00078 raise RuntimeError, "Unknown option"
00079 if necessaryKeys:
00080
00081
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
00105
00106 if arg.count('='):
00107
00108 name, value = arg.split ('=', 1)
00109 if name.count('_'):
00110
00111 name, command = name.split ('_', 1)
00112 command = command.lower()
00113 if command == 'load':
00114 self.loadFromFile (name, value)
00115 continue
00116
00117 print "Unknown command '%s' in '%s_%s" % \
00118 (command, name, command)
00119 raise RuntimeError, "Illegal parsing command"
00120 else:
00121
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
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
00137 self.setDefault (name, value)
00138 else:
00139
00140 if arg.count('_'):
00141
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
00152
00153 print "Do not understand '%s' in '%s'" % (command, arg)
00154 raise RuntimeError, "Unknown command"
00155 else:
00156
00157 command = arg.lower()
00158 if command == 'help':
00159 help = True
00160 elif command == 'print':
00161 printStatus = True
00162 else:
00163
00164 print "Do not understand command '%s'" % (arg)
00165 raise RuntimeError, "Unknown command"
00166
00167
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)
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
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
00247 if name.count ("_"):
00248 print "Error: Name can not contain '_': %s" % name
00249 raise RuntimeError, "Improper 'name'"
00250
00251 if self._register.has_key (name):
00252
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
00267
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
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
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
00300
00301 if isinstance (args, tuple) and len (args) == 1:
00302 args = args[0]
00303
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
00407 return object.__getattribute__ (self, name)
00408 else:
00409
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
00434
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
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
00467
00468
00469
00470
00471
00472 obj.parseArguments()
00473