diff --git a/Doc/lib/libgetopt.tex b/Doc/lib/libgetopt.tex index 1348921f56e..49e6e03ffd5 100644 --- a/Doc/lib/libgetopt.tex +++ b/Doc/lib/libgetopt.tex @@ -55,6 +55,18 @@ thus allowing multiple occurrences. Long and short options may be mixed. \end{funcdesc} +\begin{funcdesc}{gnu_getopt}{args, options\optional{, long_options}} +This function works like \function{getopt()}, except that GNU style +scanning mode is used by default. This means that option and +non-option arguments may be intermixed. The \function{getopt()} +function stops processing options as soon as a non-option argument is +encountered. + +If the first character of the option string is `+', or if the +environment variable POSIXLY_CORRECT is set, then option processing +stops as soon as a non-option argument is encountered. +\end{funcdesc} + \begin{excdesc}{GetoptError} This is raised when an unrecognized option is found in the argument list or when an option requiring an argument is given none. diff --git a/Lib/getopt.py b/Lib/getopt.py index 91584fe78f6..3e8b7c2d60e 100644 --- a/Lib/getopt.py +++ b/Lib/getopt.py @@ -5,20 +5,36 @@ function (including the special meanings of arguments of the form `-' and `--'). Long options similar to those supported by GNU software may be used as well via an optional third argument. This module -provides a single function and an exception: +provides two functions and an exception: getopt() -- Parse command line options +gnu_getopt() -- Like getopt(), but allow option and non-option arguments +to be intermixed. GetoptError -- exception (class) raised with 'opt' attribute, which is the option involved with the exception. """ # Long option support added by Lars Wirzenius . - +# # Gerrit Holl moved the string-based exceptions # to class-based exceptions. +# +# Peter Åstrand added gnu_getopt(). +# +# TODO for gnu_getopt(): +# +# - GNU getopt_long_only mechanism +# - allow the caller to specify ordering +# - RETURN_IN_ORDER option +# - GNU extension with '-' as first character of option string +# - optional arguments, specified by double colons +# - a option string with a W followed by semicolon should +# treat "-W foo" as "--foo" __all__ = ["GetoptError","error","getopt"] +import os + class GetoptError(Exception): opt = '' msg = '' @@ -75,6 +91,56 @@ def getopt(args, shortopts, longopts = []): return opts, args +def gnu_getopt(args, shortopts, longopts = []): + """getopt(args, options[, long_options]) -> opts, args + + This function works like getopt(), except that GNU style scanning + mode is used by default. This means that option and non-option + arguments may be intermixed. The getopt() function stops + processing options as soon as a non-option argument is + encountered. + + If the first character of the option string is `+', or if the + environment variable POSIXLY_CORRECT is set, then option + processing stops as soon as a non-option argument is encountered. + + """ + + opts = [] + prog_args = [] + if type(longopts) == type(""): + longopts = [longopts] + else: + longopts = list(longopts) + + # Allow options after non-option arguments? + if shortopts.startswith('+'): + shortopts = shortopts[1:] + all_options_first = 1 + elif os.getenv("POSIXLY_CORRECT"): + all_options_first = 1 + else: + all_options_first = 0 + + while args: + if args[0] == '--': + prog_args += args[1:] + break + + if args[0][:2] == '--': + opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) + elif args[0][:1] == '-': + opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) + else: + if all_options_first: + prog_args += args + break + else: + prog_args.append(args[0]) + args = args[1:] + + return opts, prog_args + def do_longs(opts, opt, longopts, args): try: i = opt.index('=') diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index f8989f12e67..e2ae9fed418 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -4,6 +4,7 @@ import getopt from getopt import GetoptError from test_support import verify, verbose +import os def expectException(teststr, expected, failure=AssertionError): """Executes a statement passed in teststr, and raises an exception @@ -106,5 +107,24 @@ def expectException(teststr, expected, failure=AssertionError): "opts, args = getopt.getopt(cmdline, 'a:b', ['alpha', 'beta'])", GetoptError) +# Test handling of GNU style scanning mode. +if verbose: + print 'Running tests on getopt.gnu_getopt' +cmdline = ['-a', 'arg1', '-b', '1', '--alpha', '--beta=2'] +# GNU style +opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta=']) +verify(opts == [('-a', ''), ('-b', '1'), ('--alpha', ''), ('--beta', '2')]) +verify(args == ['arg1']) +# Posix style via + +opts, args = getopt.gnu_getopt(cmdline, '+ab:', ['alpha', 'beta=']) +verify(opts == [('-a', '')]) +verify(args == ['arg1', '-b', '1', '--alpha', '--beta=2']) +# Posix style via POSIXLY_CORRECT +os.environ["POSIXLY_CORRECT"] = "1" +opts, args = getopt.gnu_getopt(cmdline, 'ab:', ['alpha', 'beta=']) +verify(opts == [('-a', '')]) +verify(args == ['arg1', '-b', '1', '--alpha', '--beta=2']) + + if verbose: print "Module getopt: tests completed successfully." diff --git a/Misc/ACKS b/Misc/ACKS index 86af69342e7..a19f7968a45 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -20,6 +20,7 @@ Oliver Andrich Ross Andrus Jason Asbahr David Ascher +Peter Åstrand John Aycock Donovan Baarda Alfonso Baciero diff --git a/Misc/NEWS b/Misc/NEWS index ce2b09a8d49..2d710677b5a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -130,6 +130,8 @@ Extension modules Library +- getopt.gnu_getopt was added. + - Stop using strings for exceptions. String objects used for exceptions are now classes deriving from Exception. The objects changed were: Tkinter.TclError, bdb.BdbQuit, macpath.norm_error,