CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_1/src/FWCore/ParameterSet/python/VarParsing.py

Go to the documentation of this file.
00001 import sys
00002 import os
00003 import re
00004 from pprint import pprint
00005 from FWCore.Utilities.Enumerate import Enumerate
00006 from FWCore.Utilities.FileUtils import sectionNofTotal
00007 
00008 class VarParsing (object):
00009     """Infrastructure to parse variable definitions passed to cmsRun
00010     configuration scripts"""
00011 
00012 
00013     multiplicity = Enumerate ("singleton list", "multiplicity")
00014     varType      = Enumerate ("bool int float string tagString")
00015     commaRE      = re.compile (r',')
00016     trueRE       = re.compile (r'^true$',  re.IGNORECASE)
00017     falseRE      = re.compile (r'^false$', re.IGNORECASE)
00018 
00019 
00020     def __init__ (self, *args):
00021         """Class initializer"""
00022         # Set everything up first
00023         self._singletons       = {}
00024         self._lists            = {}
00025         self._register         = {}
00026         self._beenSet          = {}
00027         self._info             = {}
00028         self._types            = {}
00029         self._maxLength        = 0
00030         self._tags             = {}
00031         self._tagOrder         = []
00032         self._noCommaSplit     = {}
00033         self._noDefaultClear   = {}
00034         self._setDuringParsing = {}
00035         self._currentlyParsing = False
00036         # now play with the rest
00037         for arg in args:
00038             lower = arg.lower()
00039             if lower == 'python':
00040                 self.register ('storePrepend',
00041                                '',
00042                                VarParsing.multiplicity.singleton,
00043                                VarParsing.varType.string,
00044                                "Prepend location of files starting "
00045                                "with '/store'")
00046                 # Don't continue because we want to process the next
00047                 # piece, too.
00048             if lower == 'analysis' or lower == 'python':
00049                 # Optionos for cmsRun or FWLite.Python
00050                 self.register ('maxEvents',
00051                                -1,
00052                                VarParsing.multiplicity.singleton,
00053                                VarParsing.varType.int,
00054                                "Number of events to process (-1 for all)")
00055                 self.register ('totalSections',
00056                                0,
00057                                VarParsing.multiplicity.singleton,
00058                                VarParsing.varType.int,
00059                                "Total number of sections")
00060                 self.register ('section',
00061                                0,
00062                                VarParsing.multiplicity.singleton,
00063                                VarParsing.varType.int,
00064                                "This section (from 1..totalSections inclusive)")
00065                 self.register ('inputFiles',
00066                                '',
00067                                VarParsing.multiplicity.list,
00068                                VarParsing.varType.string,
00069                                "Files to process")
00070                 self.register ('secondaryInputFiles',
00071                                '',
00072                                VarParsing.multiplicity.list,
00073                                VarParsing.varType.string,
00074                                "Second group of files to process (if needed)")
00075                 self.register ('filePrepend',
00076                                '',
00077                                VarParsing.multiplicity.singleton,
00078                                VarParsing.varType.string,
00079                                "String to prepend location of all files")
00080                 self.register ('outputFile',
00081                                'output.root',
00082                                VarParsing.multiplicity.singleton,
00083                                VarParsing.varType.tagString,
00084                                "Name of output file (if needed)")
00085                 self.register ('secondaryOutputFile',
00086                                '',
00087                                VarParsing.multiplicity.singleton,
00088                                VarParsing.varType.tagString,
00089                                "Name of second output file (if needed)")
00090                 self.register ('tag',
00091                                '',
00092                                VarParsing.multiplicity.singleton,
00093                                VarParsing.varType.string,
00094                                "tag to add to output filename")
00095                 self.setupTags (tag = 'numEvent%d',
00096                                 ifCond = 'maxEvents > 0',
00097                                 tagArg = 'maxEvents')
00098                 self.setupTags (tag = '%s',
00099                                 ifCond = 'tag',
00100                                 tagArg = 'tag')
00101                 continue
00102             # old, depricated, but here for compatibility of older code
00103             if lower == "standard":
00104                 # load in old standard arguments and defaults
00105                 self.register ('maxEvents',
00106                                -1,
00107                                VarParsing.multiplicity.singleton,
00108                                VarParsing.varType.int,
00109                                "Number of events to process (-1 for all)")
00110                 self.register ('files',
00111                                '',
00112                                VarParsing.multiplicity.list,
00113                                VarParsing.varType.string,
00114                                "Files to process")
00115                 self.register ('secondaryFiles',
00116                                '',
00117                                VarParsing.multiplicity.list,
00118                                VarParsing.varType.string,
00119                                "Second group of files to process (if needed)")
00120                 self.register ('output',
00121                                'output.root',
00122                                VarParsing.multiplicity.singleton,
00123                                VarParsing.varType.tagString,
00124                                "Name of output file (if needed)")
00125                 self.register ('secondaryOutput',
00126                                '',
00127                                VarParsing.multiplicity.singleton,
00128                                VarParsing.varType.tagString,
00129                                "Name of second output file (if needed)")
00130                 self.setupTags (tag = 'numEvent%d',
00131                                 ifCond = 'maxEvents > 0',
00132                                 tagArg = 'maxEvents')
00133                 continue
00134             # if we're still here, then we've got a rogue arument
00135             print "Error: VarParsing.__init__ doesn't understand '%s'" \
00136                   % arg
00137             raise RuntimeError, "Failed to create VarParsing object"
00138 
00139 
00140     def setupTags (self, **kwargs):
00141         """Sets up information for tags for output names"""
00142         necessaryKeys = set (['ifCond', 'tag'])
00143         allowedKeys   = set (['tagArg'])
00144         for key in kwargs.keys():
00145             if key in allowedKeys:
00146                 continue
00147             if key in necessaryKeys:
00148                 necessaryKeys.remove (key)
00149                 continue
00150             # if we're here, then we have a key that's not understood
00151             print "Unknown option '%s'" % key
00152             raise RuntimeError, "Unknown option"
00153         if necessaryKeys:
00154             # if this is not empty, then we didn't have a key that was
00155             # necessary.
00156             print "Missing keys: %s" % necessaryKeys
00157             raise runtimeError, "Missing keys"
00158         tag = kwargs.get('tag')
00159         del kwargs['tag']
00160         self._tags[tag] = kwargs
00161         self._tagOrder.append (tag)
00162 
00163 
00164     def parseArguments (self):
00165         """Parses command line arguments.  Parsing starts just after
00166         the name of the configuration script.  Parsing will fail if
00167         there is not 'xxxx.py'"""
00168         self._currentlyParsing = True
00169         foundPy      = False
00170         printStatus  = False
00171         help         = False
00172         singleAssign = True 
00173         for arg in sys.argv:
00174             if not foundPy and arg.endswith ('.py'):
00175                 foundPy = True
00176                 continue
00177             if not foundPy:
00178                 continue
00179             # If we're here, then we can parse to our hearts content.
00180             # So, is this a command or a declaration?
00181             if arg.count('='):
00182                 # declaration
00183                 name, value = arg.split ('=', 1)
00184                 if name.count('_'):
00185                     # name with command
00186                     name, command = name.split ('_', 1)
00187                     command = command.lower()
00188                     if command == 'load':
00189                         self.loadFromFile (name, value)
00190                         continue
00191                     if command == 'clear':
00192                         self.clearList (name)
00193                         continue
00194                     # If we're here, then I don't recognize this command
00195                     print "Unknown command '%s' in '%s_%s" % \
00196                           (command, name, command)
00197                     raise RuntimeError, "Illegal parsing command"
00198                 else:
00199                     # just a name and value
00200                     if not self._register.has_key (name):
00201                         print "Error:  '%s' not registered." \
00202                               % name
00203                         raise RuntimeError, "Unknown variable"
00204                     if VarParsing.multiplicity.singleton == \
00205                            self._register[name]:
00206                         # singleton
00207                         if self._beenSet.get (name) and singleAssign:
00208                             print "Variable '%s' assigned multiple times. Use" \
00209                                   , "'multipleAssign' command to avoid"
00210                             raise RuntimeError, "Multiple assignment"
00211                         self._beenSet[name] = True
00212                         self.setDefault (name, value)
00213                     else:
00214                         # list
00215                         self.setDefault (name, value)
00216             else:
00217                 # commands
00218                 if arg.count('_'):
00219                     # name modifier
00220                     name, command = arg.split ('_', 1)
00221                     command = command.lower()
00222                     if not self._register.has_key (name):
00223                         print "Error:  '%s' not registered." \
00224                               % name
00225                         raise RuntimeError, "Unknown variable"
00226                     if command == 'clear':
00227                         self.clearList (name)
00228                         continue
00229                     # if we're still here, complain that we don't
00230                     # understand this command:
00231                     print "Do not understand '%s' in '%s'" % (command, arg)
00232                     raise RuntimeError, "Unknown command"
00233                 else:
00234                     # simple command
00235                     command = arg.lower()
00236                     if command == 'help' or command == '--help':
00237                         help = True
00238                     elif command == 'print' or command == '--print':
00239                         printStatus = True
00240                     elif command == 'noprint' or command == '--noprint':
00241                         printStatus = False
00242                     else:
00243                         # We don't understand this command
00244                         print "Do not understand command '%s'" % (arg)
00245                         raise RuntimeError, "Unknown command"
00246             # else if declaration
00247         ###########################
00248         # Post-loading processing #
00249         ###########################
00250         # sections
00251         if self._register.has_key ('totalSections') and \
00252            self._register.has_key ('section') and \
00253            self._register.has_key ('inputFiles') and \
00254            self.totalSections and self.section:
00255             # copy list
00256             oldInputFiles = self.inputFiles
00257             # clear list
00258             self.clearList ('inputFiles')
00259             # used old list to make list
00260             self.inputFiles = sectionNofTotal (oldInputFiles,
00261                                                self.section,
00262                                                self.totalSections)
00263         # storePrepend
00264         if self._register.has_key ('storePrepend') and \
00265            self._register.has_key ('inputFiles') and \
00266            self.storePrepend:
00267             storeRE = re.compile (r'^/store/')
00268             newFileList = []
00269             for filename in self.inputFiles:
00270                 if storeRE.match (filename):
00271                     filename = self.storePrepend + filename
00272                 newFileList.append (filename)
00273             # clear old list
00274             self.clearList ('inputFiles')
00275             # set new list as list
00276             self.inputFiles = newFileList
00277         # filePrepend
00278         if self._register.has_key ('filePrepend') and \
00279            self._register.has_key ('inputFiles') and \
00280            self.filePrepend:
00281             newFileList = []
00282             for filename in self.inputFiles:
00283                 filename = self.filePrepend + filename
00284                 newFileList.append (filename)
00285             # clear old list
00286             self.clearList ('inputFiles')
00287             # set new list as list
00288             self.inputFiles = newFileList
00289         # make sure found the py file
00290         if not foundPy:
00291             print "VarParsing.parseArguments() Failure: No configuration " + \
00292                   "file found ending in .py."
00293             raise RuntimeError, "Invalid configuration ending"
00294         if help:
00295             self.help()
00296         if printStatus:
00297             print self
00298         self._currentlyParsing = False
00299 
00300 
00301     def clearList (self, name):
00302         """Empties all entries from list"""
00303         if not self._register.has_key (name):
00304             print "Error:  '%s' not registered." \
00305                   % name
00306             raise RuntimeError, "Unknown variable"
00307         if self._register[name] != VarParsing.multiplicity.list:
00308             print "Error: '%s' is not a list" % name
00309             raise RuntimeError, "Faulty 'clear' command"
00310         # if we're still here, do what we came to do
00311         self._lists[name] = []
00312 
00313 
00314     def setNoDefaultClear (self, name, value=True):
00315         """Tells lists to not clear default list values when set from
00316         command line."""
00317         if not self._register.has_key (name):
00318             print "Error:  '%s' not registered." \
00319                   % name
00320             raise RuntimeError, "Unknown variable"
00321         if self._register[name] != VarParsing.multiplicity.list:
00322             print "Error: '%s' is not a list" % name
00323             raise RuntimeError, "Faulty 'setNoDefaultClear' command"
00324         self._noDefaultClear[name] = bool (value)
00325 
00326 
00327     def setNoCommaSplit (self, name, value=True):
00328         """Tells lists to not split up values by commas."""
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 not a list" % name
00335             raise RuntimeError, "Faulty 'setNoCommaSplit' command"
00336         self._noCommaSplit[name] = bool (value)
00337 
00338 
00339     def loadFromFile (self, name, filename):
00340         """Loads a list from file"""
00341         if not self._register.has_key (name):
00342             print "Error:  '%s' not registered." \
00343                   % name
00344             raise RuntimeError, "Unknown variable"
00345         if self._register[name] != VarParsing.multiplicity.list:
00346             print "Error: '%s' is not a list" % name
00347             raise RuntimeError, "'load' only works for lists"
00348         filename = os.path.expanduser (filename)
00349         if not os.path.exists (filename):
00350             print "Error: '%s' file does not exist."
00351             raise RuntimeError, "Bad filename"
00352         source = open (filename, 'r')        
00353         for line in source.readlines():
00354             line = re.sub (r'#.+$', '', line) # remove comment characters
00355             line = line.strip()
00356             if len (line):
00357                 self._lists[name].append( self._convert (name, line ) )
00358         source.close()
00359 
00360 
00361     def help (self):
00362         """Prints out help information and exits"""
00363         print self
00364         print """Options:
00365         help           : This screen
00366         multipleAssign : Allows singletons to have multiple assigments
00367         print          : Prints out current values
00368         XXX_clear      : Clears list named 'XXX'
00369         """    
00370         sys.exit (0)
00371 
00372 
00373     def register (self, name,
00374                   default = "",
00375                   mult    = multiplicity.singleton,
00376                   mytype  = varType.int,
00377                   info    = "",
00378                   **kwargs):
00379         """Register a variable"""
00380         # is type ok?
00381         if not VarParsing.multiplicity.isValidValue (mult):
00382             print "Error: VarParsing.register() must use ",\
00383                   "VarParsing.multiplicity."
00384             raise RuntimeError, "Improper 'mult' value"
00385         if not VarParsing.varType.isValidValue (mytype):
00386             print "Error: VarParsing.register() must use ",\
00387                   "VarParsing.varType."
00388             raise RuntimeError, "Improper 'type' value %s" % mytype
00389         if VarParsing.multiplicity.list == mult and \
00390            VarParsing.varType.tagString == mytype:
00391             print "Error: 'tagString' can only be used with 'singleton'"
00392             raise RuntimeError, "Improper registration"
00393         # is the name ok
00394         if name.count ("_"):
00395             print "Error: Name can not contain '_': %s" % name
00396             raise RuntimeError, "Improper 'name'"
00397         # has this been registered before?
00398         if self._register.has_key (name):
00399             # Uh oh
00400             print "Error: You can not register a name twice, '%s'" \
00401                   % name
00402             raise RuntimeError, "Attempt to re-register variable"
00403         self._register[name] = mult
00404         self._beenSet[name]  = False
00405         self._info[name]     = info
00406         self._types[name]    = mytype
00407         if len (name) > self._maxLength:
00408             self._maxLength = len (name)
00409         if VarParsing.multiplicity.singleton == mult:
00410             self._singletons[name] = default
00411         else:
00412             self._lists[name] = []
00413             # if it's a list, we only want to use the default if it
00414             # does exist.
00415             if len (default):
00416                 self._lists[name].append (default)
00417         #######################################
00418         ## Process any additional directives ##
00419         #######################################
00420         # do we want to tell the list to not split command line
00421         # arguments by commas?
00422         if kwargs.get ('noCommaSplit'):
00423             self._noCommaSplit[name] = bool( kwargs['noCommaSplit'] )
00424             del kwargs['noCommaSplit']
00425         if kwargs.get ('noDefaultClear'):
00426             self._noDefaultClear[name] = bool( kwargs['noDefaultClear'] )
00427             del kwargs['noDefaultClear']
00428         if len (kwargs):
00429             raise RuntimeError, "register() Unknown arguments %s" % kwargs
00430 
00431 
00432     def has_key (self, key):
00433         """Returns true if a key is registered"""
00434         return self._register.has_key (key)
00435 
00436 
00437     def setType (self, name, mytype):
00438         """Change the type of 'name' to 'mytype'"""
00439         if not VarParsing.varType.isValidValue (mytype):
00440             print "Error: VarParsing.setType() must use ",\
00441                   "VarParsing.varType."
00442             raise RuntimeError, "Improper 'type' value"
00443         oldVal = self.__getattr__ (name, noTags = True)
00444         self._types[name] = mytype
00445         self.setDefault (name, oldVal)
00446         
00447 
00448     def setDefault (self, name, *args):
00449         """Used to set or change the default of an already registered
00450         name"""
00451         # has this been registered?
00452         if not self._register.has_key (name):
00453             print "Error: VarParsing.setDefault '%s' not already registered." \
00454                   % name
00455             raise RuntimeError, "setDefault without registration"
00456         if VarParsing.multiplicity.singleton == self._register[name]:
00457             # make sure we only have one value
00458             if len (args) != 1:
00459                 print "Error: VarParsing.setDefault needs exactly 1 ",\
00460                       "value for '%s'" % name
00461                 raise RuntimeError, "setDefault args problem"
00462             self._singletons[name] = self._convert (name, args[0])
00463         else:
00464             # If:
00465             #   - We have a list (which we do)
00466             #   - We are now processing command line parsing
00467             #   - It has not yet been set after parsing
00468             #   - We have not explicitly asked for it to be NOT cleared
00469             # Then:
00470             #   - We clear the list
00471             if self._currentlyParsing and \
00472                not self._setDuringParsing.get(name) and \
00473                not self._noDefaultClear.get(name):
00474                 # All four conditions have been satisfied, so let's go
00475                 # ahead and clear this.
00476                 self.clearList (name)
00477             # IF we are currently parsing, then tell people I've set
00478             # this:
00479             if self._currentlyParsing:
00480                 self._setDuringParsing[name] = True
00481             # if args is a tuple and it only has one entry, get rid of
00482             # the first level of tupleness:
00483             if isinstance (args, tuple) and len (args) == 1:
00484                 args = args[0]
00485             # is this still a tuple
00486             if isinstance (args, tuple):
00487                 mylist = list (args)
00488             elif isinstance (args, list):
00489                 mylist = args
00490             else:
00491                 mylist = []
00492                 mylist.append (args)
00493             if not self._noCommaSplit.get (name):
00494                 oldList = mylist
00495                 mylist = []
00496                 for item in oldList:
00497                     mylist.extend( VarParsing.commaRE.split( item ) )
00498             for item in mylist:
00499                 self._lists[name].append( self._convert (name, item ) )
00500 
00501 
00502     def _convert (self, name, inputVal):
00503         """Converts inputVal to the type required by name"""
00504         inputVal = str (inputVal)
00505         if self._types[name] == VarParsing.varType.bool:
00506             if VarParsing.trueRE.match (inputVal) or '1' == inputVal:
00507                 return True
00508             elif VarParsing.falseRE.match (inputVal) or '0' == inputVal:
00509                 return False
00510             # if we're still here, then we don't have 'true' or 'false'
00511             raise RuntimeError, "Unknown bool value '%s'.  Must be 'true' or 'false'" % inputVal
00512         if self._types[name] == VarParsing.varType.string or \
00513            self._types[name] == VarParsing.varType.tagString:
00514             return inputVal
00515         elif self._types[name] == VarParsing.varType.int:
00516             return int (inputVal, 0)
00517         elif self._types[name] == VarParsing.varType.float:
00518             return float (inputVal)
00519         else:
00520             raise RuntimeError, "Unknown varType"
00521         
00522 
00523     def _withTags (self, name):
00524         if not self._register.has_key (name):
00525             print "Error:  '%s' not registered." \
00526                   % name
00527             raise RuntimeError, "Unknown variable"
00528         if self._register[name] == VarParsing.multiplicity.list:
00529             print "Error: '%s' is a list" % name
00530             raise RuntimeError, "withTags() only works on singletons"
00531         retval = self._singletons[name]
00532         if retval.endswith ('.root'):
00533             retval, garbage = os.path.splitext (retval)
00534         reverseOrder = self._tagOrder
00535         reverseOrder.reverse()
00536         for tag in reverseOrder:
00537             tagDict = self._tags[tag]
00538             ifCond = tagDict['ifCond']
00539             if ifCond.count('%'):
00540                 pass
00541             else:
00542                 ifCond = "self." + ifCond
00543             boolValue = eval (ifCond)
00544             tagArg = tagDict.get ('tagArg')
00545             if tagArg:
00546                 evalString = "'%s' %% self.%s" % (tag, tagArg)
00547                 tag = eval (evalString)
00548             if boolValue:
00549                 retval = retval + "_" + tag        
00550         return retval + ".root"
00551             
00552 
00553     def __str__ (self):
00554         """String form of self"""
00555         maxLen = min (self._maxLength, 20)
00556         form     = "  %%-%ds: %%s" % maxLen
00557         formInfo = "  %%%ds  - %%s" % (maxLen - 2)
00558         formItem = "  %%%ds    %%s" % (maxLen - 1)
00559         retval = ""
00560         if len (self._singletons.keys()):
00561             retval = retval + "Singletons:\n"
00562         for varName, value in sorted (self._singletons.iteritems()):
00563             retval = retval + form % (varName, value) + "\n";
00564             if self._info.get(varName):
00565                 retval = retval + formInfo % ('', self._info[varName]) + "\n"
00566         if len (self._singletons.keys()):
00567             retval = retval +  "Lists:\n"
00568         for varName, value in sorted (self._lists.iteritems()):
00569             stringValue = "%s" % value
00570             if len (stringValue) < 76 - maxLen:
00571                 retval = retval + form % (varName, value) + "\n"
00572             else:
00573                 varLength = len (value)
00574                 for index, item in enumerate (value):
00575                     if index == 0:
00576                         retval = retval + form % (varName, "['" + item)
00577                     else:
00578                         retval = retval + formItem % ('',"'" + item)
00579                     if index == varLength - 1:
00580                         retval = retval + "' ]\n"
00581                     else:
00582                         retval = retval + "',\n"
00583             if self._info.get(varName):
00584                 retval = retval + formInfo % ('', self._info[varName]) + "\n"
00585         return retval
00586 
00587 
00588     def __setattr__ (self, name, value, *extras):
00589         """Lets me set internal values, or uses setDefault"""
00590         if not name.startswith ("_"):
00591             mylist = list (extras)
00592             mylist.insert (0, value)
00593             self.setDefault (name, *mylist)
00594         else:
00595             object.__setattr__ (self, name, value)
00596 
00597 
00598     def __getattr__ (self, name, noTags = False):
00599         """Lets user get the info they want with obj.name"""
00600         if name.startswith ("_"):
00601             # internal use
00602             return object.__getattribute__ (self, name)
00603         else:
00604             # user variable
00605             if not self._register.has_key (name):
00606                 print "Error:  '%s' not already registered." \
00607                       % name
00608                 raise RuntimeError, "Unknown variable"
00609             if VarParsing.multiplicity.singleton == self._register[name]:
00610                 if VarParsing.varType.tagString == self._types[name] \
00611                        and not noTags:
00612                     return self._withTags (name)
00613                 else:
00614                     return self._singletons[name]
00615             else:
00616                 return self._lists[name]
00617  
00618 
00619 ##############################################################################
00620 ## ######################################################################## ##
00621 ## ##                                                                    ## ##
00622 ## ######################################################################## ##
00623 ##############################################################################
00624 
00625     
00626 if __name__ == "__main__":
00627     #############################################
00628     ## Load and save command line history when ##
00629     ## running interactively.                  ##
00630     #############################################
00631     import os, readline
00632     import atexit
00633     historyPath = os.path.expanduser("~/.pyhistory")
00634 
00635 
00636     def save_history(historyPath=historyPath):
00637         import readline
00638         readline.write_history_file(historyPath)
00639         if os.path.exists(historyPath):
00640             readline.read_history_file(historyPath)
00641 
00642 
00643     atexit.register(save_history)
00644     readline.parse_and_bind("set show-all-if-ambiguous on")
00645     readline.parse_and_bind("tab: complete")
00646     if os.path.exists (historyPath) :
00647         readline.read_history_file(historyPath)
00648         readline.set_history_length(-1)
00649 
00650 
00651     ############################
00652     # Example code starts here #
00653     ############################
00654 
00655     obj = VarParsing ('standard')
00656     obj.register ('someVar',
00657                   mult=VarParsing.multiplicity.singleton,
00658                   info="for testing")
00659     obj.setupTags (tag    = "someCondition",
00660                    ifCond = "someVar")
00661     ## obj.register ('numbers',
00662     ##               mult=VarParsing.multiplicity.list,
00663     ##               info="Numbers")
00664     ## obj.register ('singleNumber',
00665     ##               mult=VarParsing.multiplicity.singleton,
00666     ##               info="A single number")
00667     obj.parseArguments()
00668