[Python-Dev] Another command line parser

Greg Ewing greg@cosc.canterbury.ac.nz
Tue, 20 Aug 2002 13:09:38 +1200 (NZST)


In view of the recent discussion on command line parsers,
you may be interested in the attached module which I wrote
in response to a c.l.py posting.

The return values are designed so that they can be used
as the *args and/or **kwds arguments to a function if
desired.

#-----------------------------------------------------------------
#
#  A Pythonically minimalistic command line parser
#  Inspired by ideas from Huaiyu Zhu 
#  <huaiyu@gauss.almadan.ibm.com> and Robert Biddle
#  <Robert.Biddle@comp.vuw.ac.nz>.
#
#  Author: Greg Ewing <greg@cosc.canterbury.ac.nz>
#
#-----------------------------------------------------------------

class CommandLineError(Exception):
  pass

def clparse(switches, flags, argv = None):
  """clparse(switches, flags, argv = None)

  Parse command line arguments.

  switches = string of option characters not taking arguments
  flags = string of option characters taking an argument
  argv = command line to parse (including program name), defaults
         to sys.argv

  Returns (args, options) where:

  args = list of non-option arguments
  options = dictionary mapping switch character to number of
            occurrences of the switch, and flag character to
            list of arguments specified with that flag

  Arguments following "--" are regarded as non-option arguments
  even if they start with a hyphen.
  """
  if not argv:
    import sys
    argv = sys.argv
  argv = argv[1:]
  opts = {}
  args = []
  for c in switches:
    opts[c] = 0
  for c in flags:
    if c in switches:
      raise ValueError("'%c' both switch and flag" % c)
    opts[c] = []
  seen_dashdash = 0
  while argv:
    arg = argv.pop(0)
    if arg == "--":
      seen_dashdash = 1
    elif not seen_dashdash and arg.startswith("-"):
      for c in arg[1:]:
        if c in switches:
          opts[c] += 1
        elif c in flags:
          try:
            val = argv.pop(0)
          except IndexError:
            raise CommandLineError("Missing argument for option -%c" % c)
          opts[c].append(val)
        else:
          raise CommandLineError("Unknown option -%c" % c)
    else:
      args.append(arg)
  return args, opts

if __name__ == "__main__":
  def spam(args, a, b, c, x, y, z):
    print "a =", a
    print "b =", b
    print "c =", c
    print "x =", x
    print "y =", y
    print "z =", z
    print "args =", args
  args, kwds = clparse("abc", "xyz")
  spam(args, **kwds)