File indexing completed on 2024-12-03 23:19:35
0001 import sys
0002 import os
0003 import re
0004 from pprint import pprint
0005 from FWCore.Utilities.Enumerate import Enumerate
0006 from FWCore.Utilities.FileUtils import sectionNofTotal
0007
0008 class VarParsing (object):
0009 """Infrastructure to parse variable definitions passed to cmsRun
0010 configuration scripts"""
0011
0012
0013 multiplicity = Enumerate ("singleton list", "multiplicity")
0014 varType = Enumerate ("bool int float string tagString")
0015 commaRE = re.compile (r',')
0016 trueRE = re.compile (r'^true$', re.IGNORECASE)
0017 falseRE = re.compile (r'^false$', re.IGNORECASE)
0018
0019
0020 def __init__ (self, *args):
0021 """Class initializer"""
0022
0023 self._singletons = {}
0024 self._lists = {}
0025 self._register = {}
0026 self._beenSet = {}
0027 self._info = {}
0028 self._types = {}
0029 self._maxLength = 0
0030 self._tags = {}
0031 self._tagOrder = []
0032 self._noCommaSplit = {}
0033 self._noDefaultClear = {}
0034 self._setDuringParsing = {}
0035 self._currentlyParsing = False
0036
0037 for arg in args:
0038 lower = arg.lower()
0039 if lower == 'python':
0040 self.register ('storePrepend',
0041 '',
0042 VarParsing.multiplicity.singleton,
0043 VarParsing.varType.string,
0044 "Prepend location of files starting "
0045 "with '/store'")
0046
0047
0048 if lower == 'analysis' or lower == 'python':
0049
0050 self.register ('maxEvents',
0051 -1,
0052 VarParsing.multiplicity.singleton,
0053 VarParsing.varType.int,
0054 "Number of events to process (-1 for all)")
0055 self.register ('totalSections',
0056 0,
0057 VarParsing.multiplicity.singleton,
0058 VarParsing.varType.int,
0059 "Total number of sections")
0060 self.register ('section',
0061 0,
0062 VarParsing.multiplicity.singleton,
0063 VarParsing.varType.int,
0064 "This section (from 1..totalSections inclusive)")
0065 self.register ('inputFiles',
0066 '',
0067 VarParsing.multiplicity.list,
0068 VarParsing.varType.string,
0069 "Files to process")
0070 self.register ('secondaryInputFiles',
0071 '',
0072 VarParsing.multiplicity.list,
0073 VarParsing.varType.string,
0074 "Second group of files to process (if needed)")
0075 self.register ('filePrepend',
0076 '',
0077 VarParsing.multiplicity.singleton,
0078 VarParsing.varType.string,
0079 "String to prepend location of all files")
0080 self.register ('outputFile',
0081 'output.root',
0082 VarParsing.multiplicity.singleton,
0083 VarParsing.varType.tagString,
0084 "Name of output file (if needed)")
0085 self.register ('secondaryOutputFile',
0086 '',
0087 VarParsing.multiplicity.singleton,
0088 VarParsing.varType.tagString,
0089 "Name of second output file (if needed)")
0090 self.register ('tag',
0091 '',
0092 VarParsing.multiplicity.singleton,
0093 VarParsing.varType.string,
0094 "tag to add to output filename")
0095 self.setupTags (tag = 'numEvent%d',
0096 ifCond = 'maxEvents > 0',
0097 tagArg = 'maxEvents')
0098 self.setupTags (tag = '%s',
0099 ifCond = 'tag',
0100 tagArg = 'tag')
0101 continue
0102
0103 if lower == "standard":
0104
0105 self.register ('maxEvents',
0106 -1,
0107 VarParsing.multiplicity.singleton,
0108 VarParsing.varType.int,
0109 "Number of events to process (-1 for all)")
0110 self.register ('files',
0111 '',
0112 VarParsing.multiplicity.list,
0113 VarParsing.varType.string,
0114 "Files to process")
0115 self.register ('secondaryFiles',
0116 '',
0117 VarParsing.multiplicity.list,
0118 VarParsing.varType.string,
0119 "Second group of files to process (if needed)")
0120 self.register ('output',
0121 'output.root',
0122 VarParsing.multiplicity.singleton,
0123 VarParsing.varType.tagString,
0124 "Name of output file (if needed)")
0125 self.register ('secondaryOutput',
0126 '',
0127 VarParsing.multiplicity.singleton,
0128 VarParsing.varType.tagString,
0129 "Name of second output file (if needed)")
0130 self.setupTags (tag = 'numEvent%d',
0131 ifCond = 'maxEvents > 0',
0132 tagArg = 'maxEvents')
0133 continue
0134
0135 print("Error: VarParsing.__init__ doesn't understand '%s'" \
0136 % arg)
0137 raise RuntimeError("Failed to create VarParsing object")
0138
0139
0140 def setupTags (self, **kwargs):
0141 """Sets up information for tags for output names"""
0142 necessaryKeys = set (['ifCond', 'tag'])
0143 allowedKeys = set (['tagArg'])
0144 for key in kwargs.keys():
0145 if key in allowedKeys:
0146 continue
0147 if key in necessaryKeys:
0148 necessaryKeys.remove (key)
0149 continue
0150
0151 print("Unknown option '%s'" % key)
0152 raise RuntimeError("Unknown option")
0153 if necessaryKeys:
0154
0155
0156 print("Missing keys: %s" % necessaryKeys)
0157 raise runtimeError("Missing keys")
0158 tag = kwargs.get('tag')
0159 del kwargs['tag']
0160 self._tags[tag] = kwargs
0161 self._tagOrder.append (tag)
0162
0163
0164 def parseArguments (self):
0165 """Parses command line arguments. Parsing starts just after
0166 the name of the configuration script. Parsing will fail if
0167 there is not 'xxxx.py'"""
0168 self._currentlyParsing = True
0169 foundPy = False
0170 printStatus = False
0171 help = False
0172 singleAssign = True
0173 for arg in sys.argv:
0174 if not foundPy and arg.endswith ('.py'):
0175 foundPy = True
0176 continue
0177 if not foundPy:
0178 continue
0179
0180
0181 if arg.count('='):
0182
0183 name, value = arg.split ('=', 1)
0184 if name.count('_'):
0185
0186 name, command = name.split ('_', 1)
0187 command = command.lower()
0188 if command == 'load':
0189 self.loadFromFile (name, value)
0190 continue
0191 if command == 'clear':
0192 self.clearList (name)
0193 continue
0194
0195 print("Unknown command '%s' in '%s_%s" % \
0196 (command, name, command))
0197 raise RuntimeError("Illegal parsing command")
0198 else:
0199
0200 if name not in self._register:
0201 print("Error: '%s' not registered." \
0202 % name)
0203 raise RuntimeError("Unknown variable")
0204 if VarParsing.multiplicity.singleton == \
0205 self._register[name]:
0206
0207 if self._beenSet.get (name) and singleAssign:
0208 print("Variable '%s' assigned multiple times. Use" \
0209 , "'multipleAssign' command to avoid")
0210 raise RuntimeError("Multiple assignment")
0211 self._beenSet[name] = True
0212 self.setDefault (name, value)
0213 else:
0214
0215 self.setDefault (name, value)
0216 else:
0217
0218 if arg.count('_'):
0219
0220 name, command = arg.split ('_', 1)
0221 command = command.lower()
0222 if name not in self._register:
0223 print("Error: '%s' not registered." \
0224 % name)
0225 raise RuntimeError("Unknown variable")
0226 if command == 'clear':
0227 self.clearList (name)
0228 continue
0229
0230
0231 print("Do not understand '%s' in '%s'" % (command, arg))
0232 raise RuntimeError("Unknown command")
0233 else:
0234
0235 command = arg.lower()
0236 if command == 'help' or command == '--help':
0237 help = True
0238 elif command == 'print' or command == '--print':
0239 printStatus = True
0240 elif command == 'noprint' or command == '--noprint':
0241 printStatus = False
0242 else:
0243
0244 print("Do not understand command '%s'" % (arg))
0245 raise RuntimeError("Unknown command")
0246
0247
0248
0249
0250
0251 if 'totalSections' in self._register and \
0252 'section' in self._register and \
0253 'inputFiles' in self._register and \
0254 self.totalSections and self.section:
0255
0256 oldInputFiles = self.inputFiles
0257
0258 self.clearList ('inputFiles')
0259
0260 self.inputFiles = sectionNofTotal (oldInputFiles,
0261 self.section,
0262 self.totalSections)
0263
0264 if 'storePrepend' in self._register and \
0265 'inputFiles' in self._register and \
0266 self.storePrepend:
0267 storeRE = re.compile (r'^/store/')
0268 newFileList = []
0269 for filename in self.inputFiles:
0270 if storeRE.match (filename):
0271 filename = self.storePrepend + filename
0272 newFileList.append (filename)
0273
0274 self.clearList ('inputFiles')
0275
0276 self.inputFiles = newFileList
0277
0278 if 'filePrepend' in self._register and \
0279 'inputFiles' in self._register and \
0280 self.filePrepend:
0281 newFileList = []
0282 for filename in self.inputFiles:
0283 filename = self.filePrepend + filename
0284 newFileList.append (filename)
0285
0286 self.clearList ('inputFiles')
0287
0288 self.inputFiles = newFileList
0289
0290 if not foundPy:
0291 print("VarParsing.parseArguments() Failure: No configuration " + \
0292 "file found ending in .py.")
0293 raise RuntimeError("Invalid configuration ending")
0294 if help:
0295 self.help()
0296 if printStatus:
0297 print(self)
0298 self._currentlyParsing = False
0299
0300
0301 def clearList (self, name):
0302 """Empties all entries from list"""
0303 if name not in self._register:
0304 print("Error: '%s' not registered." \
0305 % name)
0306 raise RuntimeError("Unknown variable")
0307 if self._register[name] != VarParsing.multiplicity.list:
0308 print("Error: '%s' is not a list" % name)
0309 raise RuntimeError("Faulty 'clear' command")
0310
0311 self._lists[name] = []
0312
0313
0314 def setNoDefaultClear (self, name, value=True):
0315 """Tells lists to not clear default list values when set from
0316 command line."""
0317 if name not in self._register:
0318 print("Error: '%s' not registered." \
0319 % name)
0320 raise RuntimeError("Unknown variable")
0321 if self._register[name] != VarParsing.multiplicity.list:
0322 print("Error: '%s' is not a list" % name)
0323 raise RuntimeError("Faulty 'setNoDefaultClear' command")
0324 self._noDefaultClear[name] = bool (value)
0325
0326
0327 def setNoCommaSplit (self, name, value=True):
0328 """Tells lists to not split up values by commas."""
0329 if name not in self._register:
0330 print("Error: '%s' not registered." \
0331 % name)
0332 raise RuntimeError("Unknown variable")
0333 if self._register[name] != VarParsing.multiplicity.list:
0334 print("Error: '%s' is not a list" % name)
0335 raise RuntimeError("Faulty 'setNoCommaSplit' command")
0336 self._noCommaSplit[name] = bool (value)
0337
0338
0339 def loadFromFile (self, name, filename):
0340 """Loads a list from file"""
0341 if name not in self._register:
0342 print("Error: '%s' not registered." \
0343 % name)
0344 raise RuntimeError("Unknown variable")
0345 if self._register[name] != VarParsing.multiplicity.list:
0346 print("Error: '%s' is not a list" % name)
0347 raise RuntimeError("'load' only works for lists")
0348 filename = os.path.expanduser (filename)
0349 if not os.path.exists (filename):
0350 print("Error: '%s' file does not exist.")
0351 raise RuntimeError("Bad filename")
0352 source = open (filename, 'r')
0353 for line in source.readlines():
0354 line = re.sub (r'#.+$', '', line)
0355 line = line.strip()
0356 if len (line):
0357 self._lists[name].append( self._convert (name, line ) )
0358 source.close()
0359
0360
0361 def help (self):
0362 """Prints out help information and exits"""
0363 print(self)
0364 print("""Options:
0365 help : This screen
0366 multipleAssign : Allows singletons to have multiple assignments
0367 print : Prints out current values
0368 XXX_clear : Clears list named 'XXX'
0369 """)
0370 sys.exit (0)
0371
0372
0373 def register (self, name,
0374 default = "",
0375 mult = multiplicity.singleton,
0376 mytype = varType.int,
0377 info = "",
0378 **kwargs):
0379 """Register a variable"""
0380
0381 if not VarParsing.multiplicity.isValidValue (mult):
0382 print("Error: VarParsing.register() must use ",\
0383 "VarParsing.multiplicity.")
0384 raise RuntimeError("Improper 'mult' value")
0385 if not VarParsing.varType.isValidValue (mytype):
0386 print("Error: VarParsing.register() must use ",\
0387 "VarParsing.varType.")
0388 raise RuntimeError("Improper 'type' value %s" % mytype)
0389 if VarParsing.multiplicity.list == mult and \
0390 VarParsing.varType.tagString == mytype:
0391 print("Error: 'tagString' can only be used with 'singleton'")
0392 raise RuntimeError("Improper registration")
0393
0394 if name.count ("_"):
0395 print("Error: Name can not contain '_': %s" % name)
0396 raise RuntimeError("Improper 'name'")
0397
0398 if name in self._register:
0399
0400 print("Error: You can not register a name twice, '%s'" \
0401 % name)
0402 raise RuntimeError("Attempt to re-register variable")
0403 self._register[name] = mult
0404 self._beenSet[name] = False
0405 self._info[name] = info
0406 self._types[name] = mytype
0407 if len (name) > self._maxLength:
0408 self._maxLength = len (name)
0409 if VarParsing.multiplicity.singleton == mult:
0410 self._singletons[name] = default
0411 else:
0412 self._lists[name] = []
0413
0414
0415 if (mytype in [VarParsing.varType.bool, VarParsing.varType.int, VarParsing.varType.float] and \
0416 default not in ["",[]]) or len (default):
0417 self._lists[name].append (default)
0418
0419
0420
0421
0422
0423 if kwargs.get ('noCommaSplit'):
0424 self._noCommaSplit[name] = bool( kwargs['noCommaSplit'] )
0425 del kwargs['noCommaSplit']
0426 if kwargs.get ('noDefaultClear'):
0427 self._noDefaultClear[name] = bool( kwargs['noDefaultClear'] )
0428 del kwargs['noDefaultClear']
0429 if len (kwargs):
0430 raise RuntimeError("register() Unknown arguments %s" % kwargs)
0431
0432
0433 def has_key (self, key):
0434 """Returns true if a key is registered"""
0435 return key in self._register
0436
0437
0438 def setType (self, name, mytype):
0439 """Change the type of 'name' to 'mytype'"""
0440 if not VarParsing.varType.isValidValue (mytype):
0441 print("Error: VarParsing.setType() must use ",\
0442 "VarParsing.varType.")
0443 raise RuntimeError("Improper 'type' value")
0444 oldVal = self.__getattr__ (name, noTags = True)
0445 self._types[name] = mytype
0446 self.setDefault (name, oldVal)
0447
0448
0449 def setDefault (self, name, *args):
0450 """Used to set or change the default of an already registered
0451 name"""
0452
0453 if name not in self._register:
0454 print("Error: VarParsing.setDefault '%s' not already registered." \
0455 % name)
0456 raise RuntimeError("setDefault without registration")
0457 if VarParsing.multiplicity.singleton == self._register[name]:
0458
0459 if len (args) != 1:
0460 print("Error: VarParsing.setDefault needs exactly 1 ",\
0461 "value for '%s'" % name)
0462 raise RuntimeError("setDefault args problem")
0463 self._singletons[name] = self._convert (name, args[0])
0464 else:
0465
0466
0467
0468
0469
0470
0471
0472 if self._currentlyParsing and \
0473 not self._setDuringParsing.get(name) and \
0474 not self._noDefaultClear.get(name):
0475
0476
0477 self.clearList (name)
0478
0479
0480 if self._currentlyParsing:
0481 self._setDuringParsing[name] = True
0482
0483
0484 if isinstance (args, tuple) and len (args) == 1:
0485 args = args[0]
0486
0487 if isinstance (args, tuple):
0488 mylist = list (args)
0489 elif isinstance (args, list):
0490 mylist = args
0491 else:
0492 mylist = []
0493 mylist.append (args)
0494 if not self._noCommaSplit.get (name):
0495 oldList = mylist
0496 mylist = []
0497 for item in oldList:
0498 mylist.extend( VarParsing.commaRE.split( item ) )
0499 for item in mylist:
0500 self._lists[name].append( self._convert (name, item ) )
0501
0502
0503 def _convert (self, name, inputVal):
0504 """Converts inputVal to the type required by name"""
0505 inputVal = str (inputVal)
0506 if self._types[name] == VarParsing.varType.bool:
0507 if VarParsing.trueRE.match (inputVal) or '1' == inputVal:
0508 return True
0509 elif VarParsing.falseRE.match (inputVal) or '0' == inputVal:
0510 return False
0511
0512 raise RuntimeError("Unknown bool value '%s'. Must be 'true' or 'false'" % inputVal)
0513 if self._types[name] == VarParsing.varType.string or \
0514 self._types[name] == VarParsing.varType.tagString:
0515 return inputVal
0516 elif self._types[name] == VarParsing.varType.int:
0517 return int (inputVal, 0)
0518 elif self._types[name] == VarParsing.varType.float:
0519 return float (inputVal)
0520 else:
0521 raise RuntimeError("Unknown varType")
0522
0523
0524 def _withTags (self, name):
0525 if name not in self._register:
0526 print("Error: '%s' not registered." \
0527 % name)
0528 raise RuntimeError("Unknown variable")
0529 if self._register[name] == VarParsing.multiplicity.list:
0530 print("Error: '%s' is a list" % name)
0531 raise RuntimeError("withTags() only works on singletons")
0532 retval = self._singletons[name]
0533 if retval.endswith ('.root'):
0534 retval, garbage = os.path.splitext (retval)
0535 reverseOrder = self._tagOrder
0536 reverseOrder.reverse()
0537 for tag in reverseOrder:
0538 tagDict = self._tags[tag]
0539 ifCond = tagDict['ifCond']
0540 if ifCond.count('%'):
0541 pass
0542 else:
0543 ifCond = "self." + ifCond
0544 boolValue = eval (ifCond)
0545 tagArg = tagDict.get ('tagArg')
0546 if tagArg:
0547 evalString = "'%s' %% self.%s" % (tag, tagArg)
0548 tag = eval (evalString)
0549 if boolValue:
0550 retval = retval + "_" + tag
0551 return retval + ".root"
0552
0553
0554 def __str__ (self):
0555 """String form of self"""
0556 maxLen = min (self._maxLength, 20)
0557 form = " %%-%ds: %%s" % maxLen
0558 formInfo = " %%%ds - %%s" % (maxLen - 2)
0559 formItem = " %%%ds %%s" % (maxLen - 1)
0560 retval = ""
0561 if len (self._singletons):
0562 retval = retval + "Singletons:\n"
0563 for varName, value in sorted (self._singletons.items()):
0564 retval = retval + form % (varName, value) + "\n";
0565 if self._info.get(varName):
0566 retval = retval + formInfo % ('', self._info[varName]) + "\n"
0567 if len (self._singletons):
0568 retval = retval + "Lists:\n"
0569 for varName, value in sorted (self._lists.items()):
0570 stringValue = "%s" % value
0571 if len (stringValue) < 76 - maxLen:
0572 retval = retval + form % (varName, value) + "\n"
0573 else:
0574 varLength = len (value)
0575 for index, item in enumerate (value):
0576 if index == 0:
0577 retval = retval + form % (varName, "['" + item)
0578 else:
0579 retval = retval + formItem % ('',"'" + item)
0580 if index == varLength - 1:
0581 retval = retval + "' ]\n"
0582 else:
0583 retval = retval + "',\n"
0584 if self._info.get(varName):
0585 retval = retval + formInfo % ('', self._info[varName]) + "\n"
0586 return retval
0587
0588
0589 def __setattr__ (self, name, value, *extras):
0590 """Lets me set internal values, or uses setDefault"""
0591 if not name.startswith ("_"):
0592 mylist = list (extras)
0593 mylist.insert (0, value)
0594 self.setDefault (name, *mylist)
0595 else:
0596 object.__setattr__ (self, name, value)
0597
0598
0599 def __getattr__ (self, name, noTags = False):
0600 """Lets user get the info they want with obj.name"""
0601 if name.startswith ("_"):
0602
0603 return object.__getattribute__ (self, name)
0604 else:
0605
0606 if name not in self._register:
0607 print("Error: '%s' not already registered." \
0608 % name)
0609 raise RuntimeError("Unknown variable")
0610 if VarParsing.multiplicity.singleton == self._register[name]:
0611 if VarParsing.varType.tagString == self._types[name] \
0612 and not noTags:
0613 return self._withTags (name)
0614 else:
0615 return self._singletons[name]
0616 else:
0617 return self._lists[name]
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627 if __name__ == "__main__":
0628
0629
0630
0631
0632 import os, readline
0633 import atexit
0634 historyPath = os.path.expanduser("~/.pyhistory")
0635
0636
0637 def save_history(historyPath=historyPath):
0638 import readline
0639 readline.write_history_file(historyPath)
0640 if os.path.exists(historyPath):
0641 readline.read_history_file(historyPath)
0642
0643
0644 atexit.register(save_history)
0645 readline.parse_and_bind("set show-all-if-ambiguous on")
0646 readline.parse_and_bind("tab: complete")
0647 if os.path.exists (historyPath) :
0648 readline.read_history_file(historyPath)
0649 readline.set_history_length(-1)
0650
0651
0652
0653
0654
0655
0656 obj = VarParsing ('standard')
0657 obj.register ('someVar',
0658 mult=VarParsing.multiplicity.singleton,
0659 info="for testing")
0660 obj.setupTags (tag = "someCondition",
0661 ifCond = "someVar")
0662
0663
0664
0665
0666
0667
0668 obj.parseArguments()
0669