getopt patch

Juergen A. Erhard jae at ilk.de
Thu Dec 9 13:25:38 EST 1999


Hi,

Getopt as in python 1.5.2 is incomplete (compared even to
getopt/getopt_long in glibc2).

I've looked at some of the alternative getopts, but found that they
deviate too much from getopt's simple interface.

So, I decided to hack getopt.py itself.  Here's a list of the changes:

  + correctly (I hope) handles options following arguments.  That's

       prog arg1 arg2 --option

    The old getopt treated the --differently as an argument.

  + handles long options with conditional arguments.  Instead of a
    "=", you append ":" for those.  So,

       getopt.getopt(sys.argv[1:], "", ["verbose:"])

    would accept both `--verbose=extreme' and `--verbose'.

    (Sorry, short options not handled... I tend not to use them anyway)

Those were the things I *wanted* real bad.  Now for the fun stuff
(while I was hacking it...)

  + setting getopt.return_dictionary makes getopt return the options
    as a dictionary instead of a list.

    Multiple occurences of the same option are collected in a list.
    So, for

       prog --long --long

    we'd get

       ({'--long': ['', '']}, [])

  + setting getopt.return_dictionary_all_lists is similar to
    return_dictionary, but the values in the dict are all guaranteed
    to be lists (even single strings).

    Might be more handy than return_dictionary alone...

  + setting getopt.return_in_order makes getopt return one list with
    all the arguments and options in the order in which they appear on
    the command line.

And now, without further ado, here's the diff (and remember,
corrections and further patches are always welcome...)

8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<

--- getopt.py	1999/12/09 16:54:47	1.1
+++ getopt.py	1999/12/09 18:16:47
@@ -17,6 +17,15 @@ import string
 
 error = 'getopt.error'
 
+version = "19991209"
+
+# Return options as a dictionary
+return_dictionary = 0
+# All entries in the dict are lists (even if there's only one element
+return_dictionary_all_lists = 0
+# Return only one list, with opts and pure args in order
+return_in_order = 0
+
 def getopt(args, shortopts, longopts = []):
     """getopt(args, options[, long_options]) -> opts, args
 
@@ -50,16 +59,47 @@ def getopt(args, shortopts, longopts = [
     else:
         longopts = list(longopts)
     longopts.sort()
-    while args and args[0][:1] == '-' and args[0] != '-':
+    if not return_in_order:
+        newargs = []
+    while args:
+        # -- terminates option processing
         if args[0] == '--':
-            args = args[1:]
+            if return_in_order:
+                opts = opts + args[1:]
+            else:
+                newargs = newargs + args[1:]
             break
         if args[0][:2] == '--':
             opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
-        else:
+        elif args[0][:1] == '-':
             opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
+        else:
+            if return_in_order:
+                opts.append(args[0])
+            else:
+                newargs.append(args[0])
+            del args[0]
 
-    return opts, args
+    # Create result dictionary
+    if (return_dictionary or return_dictionary_all_lists) and not return_in_order:
+        optdict = {}
+        for opt, arg in opts:
+            if return_dictionary_all_lists:
+                optdict[opt] = optdict.get(opt, [])
+                optdict[opt].append(arg)
+            else:
+                if optdict.has_key(opt):
+                    if type(optdict[opt]) == type(""):
+                        optdict[opt] = [optdict[opt], arg]
+                    else:
+                        optdict[opt].append(arg)
+                else:
+                    optdict[opt] = arg
+        return optdict, newargs
+    elif return_in_order:
+        return opts
+    else:
+        return opts, newargs
 
 def do_longs(opts, opt, longopts, args):
     try:
@@ -71,6 +111,7 @@ def do_longs(opts, opt, longopts, args):
     has_arg, opt = long_has_args(opt, longopts)
     if has_arg:
         if optarg is None:
+            if has_arg == "required":
             if not args:
                 raise error, 'option --%s requires argument' % opt
             optarg, args = args[0], args[1:]
@@ -91,8 +132,10 @@ def long_has_args(opt, longopts):
         if y != '' and y != '=' and i+1 < len(longopts):
             if opt == longopts[i+1][:optlen]:
                 raise error, 'option --%s not a unique prefix' % opt
-        if longopts[i][-1:] in ('=', ):
-            return 1, longopts[i][:-1]
+        if longopts[i][-1] == "=":
+            return "required", longopts[i][:-1]
+        elif longopts[i][-1] == ":":
+            return "optional", longopts[i][:-1]
         return 0, longopts[i]
     raise error, 'option --' + opt + ' not recognized'

8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<--8<


-- 
Jürgen A. Erhard      eMail: jae at ilk.de      phone: (GERMANY) 0721 27326
         MARS: http://Juergen_Erhard.tripod.com/mars_index.html
                    "Ever wonder why the SAME PEOPLE
      make up ALL the conspiracy theories?" -- Michael K. Johnson




More information about the Python-list mailing list