Back to home page

Project CMSSW displayed by LXR

 
 

    


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         # Set everything up first
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         # now play with the rest
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                 # Don't continue because we want to process the next
0047                 # piece, too.
0048             if lower == 'analysis' or lower == 'python':
0049                 # Optionos for cmsRun or FWLite.Python
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             # old, depricated, but here for compatibility of older code
0103             if lower == "standard":
0104                 # load in old standard arguments and defaults
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             # if we're still here, then we've got a rogue arument
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             # if we're here, then we have a key that's not understood
0151             print("Unknown option '%s'" % key)
0152             raise RuntimeError("Unknown option")
0153         if necessaryKeys:
0154             # if this is not empty, then we didn't have a key that was
0155             # necessary.
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             # If we're here, then we can parse to our hearts content.
0180             # So, is this a command or a declaration?
0181             if arg.count('='):
0182                 # declaration
0183                 name, value = arg.split ('=', 1)
0184                 if name.count('_'):
0185                     # name with command
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                     # If we're here, then I don't recognize this command
0195                     print("Unknown command '%s' in '%s_%s" % \
0196                           (command, name, command))
0197                     raise RuntimeError("Illegal parsing command")
0198                 else:
0199                     # just a name and value
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                         # singleton
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                         # list
0215                         self.setDefault (name, value)
0216             else:
0217                 # commands
0218                 if arg.count('_'):
0219                     # name modifier
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                     # if we're still here, complain that we don't
0230                     # understand this command:
0231                     print("Do not understand '%s' in '%s'" % (command, arg))
0232                     raise RuntimeError("Unknown command")
0233                 else:
0234                     # simple command
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                         # We don't understand this command
0244                         print("Do not understand command '%s'" % (arg))
0245                         raise RuntimeError("Unknown command")
0246             # else if declaration
0247         ###########################
0248         # Post-loading processing #
0249         ###########################
0250         # sections
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             # copy list
0256             oldInputFiles = self.inputFiles
0257             # clear list
0258             self.clearList ('inputFiles')
0259             # used old list to make list
0260             self.inputFiles = sectionNofTotal (oldInputFiles,
0261                                                self.section,
0262                                                self.totalSections)
0263         # storePrepend
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             # clear old list
0274             self.clearList ('inputFiles')
0275             # set new list as list
0276             self.inputFiles = newFileList
0277         # filePrepend
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             # clear old list
0286             self.clearList ('inputFiles')
0287             # set new list as list
0288             self.inputFiles = newFileList
0289         # make sure found the py file
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         # if we're still here, do what we came to do
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) # remove comment characters
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         # is type ok?
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         # is the name ok
0394         if name.count ("_"):
0395             print("Error: Name can not contain '_': %s" % name)
0396             raise RuntimeError("Improper 'name'")
0397         # has this been registered before?
0398         if name in self._register:
0399             # Uh oh
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             # if it's a list, we only want to use the default if it
0414             # does exist.
0415             if (mytype in [VarParsing.varType.bool, VarParsing.varType.int, VarParsing.varType.float] and \
0416                default not in ["",[]]) or len (default): # check type to prevent TypeError for bool/int/float defaults
0417                 self._lists[name].append (default) # known bug: default can be list
0418         #######################################
0419         ## Process any additional directives ##
0420         #######################################
0421         # do we want to tell the list to not split command line
0422         # arguments by commas?
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         # has this been registered?
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             # make sure we only have one value
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             # If:
0466             #   - We have a list (which we do)
0467             #   - We are now processing command line parsing
0468             #   - It has not yet been set after parsing
0469             #   - We have not explicitly asked for it to be NOT cleared
0470             # Then:
0471             #   - We clear the list
0472             if self._currentlyParsing and \
0473                not self._setDuringParsing.get(name) and \
0474                not self._noDefaultClear.get(name):
0475                 # All four conditions have been satisfied, so let's go
0476                 # ahead and clear this.
0477                 self.clearList (name)
0478             # IF we are currently parsing, then tell people I've set
0479             # this:
0480             if self._currentlyParsing:
0481                 self._setDuringParsing[name] = True
0482             # if args is a tuple and it only has one entry, get rid of
0483             # the first level of tupleness:
0484             if isinstance (args, tuple) and len (args) == 1:
0485                 args = args[0]
0486             # is this still a tuple
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             # if we're still here, then we don't have 'true' or 'false'
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             # internal use
0603             return object.__getattribute__ (self, name)
0604         else:
0605             # user variable
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     ## Load and save command line history when ##
0630     ## running interactively.                  ##
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     # Example code starts here #
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     ## obj.register ('numbers',
0663     ##               mult=VarParsing.multiplicity.list,
0664     ##               info="Numbers")
0665     ## obj.register ('singleNumber',
0666     ##               mult=VarParsing.multiplicity.singleton,
0667     ##               info="A single number")
0668     obj.parseArguments()
0669