getopt.py 5.11 KB
Newer Older
1
"""Parser for command line options.
2 3 4 5 6 7 8 9 10

This module helps scripts to parse the command line arguments in
sys.argv.  It supports the same conventions as the Unix getopt()
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:

getopt() -- Parse command line options
11 12
GetoptError -- exception (class) raised with 'opt' attribute, which is the
option involved with the exception.
13 14 15
"""

# Long option support added by Lars Wirzenius <liw@iki.fi>.
Guido van Rossum's avatar
Guido van Rossum committed
16

17 18 19
# Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions
# to class-based exceptions.

Skip Montanaro's avatar
Skip Montanaro committed
20 21
__all__ = ["GetoptError","error","getopt"]

22 23 24
class GetoptError(Exception):
    opt = ''
    msg = ''
25 26 27 28
    def __init__(self, msg, opt):
        self.msg = msg
        self.opt = opt
        Exception.__init__(self, msg, opt)
29 30 31 32 33

    def __str__(self):
        return self.msg

error = GetoptError # backward compatibility
Guido van Rossum's avatar
Guido van Rossum committed
34

35
def getopt(args, shortopts, longopts = []):
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    """getopt(args, options[, long_options]) -> opts, args

    Parses command line options and parameter list.  args is the
    argument list to be parsed, without the leading reference to the
    running program.  Typically, this means "sys.argv[1:]".  shortopts
    is the string of option letters that the script wants to
    recognize, with options that require an argument followed by a
    colon (i.e., the same format that Unix getopt() uses).  If
    specified, longopts is a list of strings with the names of the
    long options which should be supported.  The leading '--'
    characters should not be included in the option name.  Options
    which require an argument should be followed by an equal sign
    ('=').

    The return value consists of two elements: the first is a list of
    (option, value) pairs; the second is the list of program arguments
    left after the option list was stripped (this is a trailing slice
    of the first argument).  Each option-and-value pair returned has
    the option as its first element, prefixed with a hyphen (e.g.,
    '-x'), and the option argument as its second element, or an empty
    string if the option has no argument.  The options occur in the
    list in the same order in which they were found, thus allowing
    multiple occurrences.  Long and short options may be mixed.

    """

    opts = []
    if type(longopts) == type(""):
        longopts = [longopts]
    else:
        longopts = list(longopts)
Tim Peters's avatar
Tim Peters committed
67
    while args and args[0].startswith('-') and args[0] != '-':
68 69 70
        if args[0] == '--':
            args = args[1:]
            break
Fred Drake's avatar
Fred Drake committed
71
        if args[0].startswith('--'):
72
            opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
73
        else:
74
            opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
Guido van Rossum's avatar
Guido van Rossum committed
75

76
    return opts, args
77

78
def do_longs(opts, opt, longopts, args):
Guido van Rossum's avatar
Guido van Rossum committed
79
    try:
80
        i = opt.index('=')
Guido van Rossum's avatar
Guido van Rossum committed
81
    except ValueError:
82
        optarg = None
Tim Peters's avatar
Tim Peters committed
83 84
    else:
        opt, optarg = opt[:i], opt[i+1:]
Guido van Rossum's avatar
Guido van Rossum committed
85 86 87

    has_arg, opt = long_has_args(opt, longopts)
    if has_arg:
88 89
        if optarg is None:
            if not args:
90
                raise GetoptError('option --%s requires argument' % opt, opt)
91
            optarg, args = args[0], args[1:]
Guido van Rossum's avatar
Guido van Rossum committed
92
    elif optarg:
93
        raise GetoptError('option --%s must not have an argument' % opt, opt)
94 95
    opts.append(('--' + opt, optarg or ''))
    return opts, args
96 97 98 99 100

# Return:
#   has_arg?
#   full option name
def long_has_args(opt, longopts):
101 102
    possibilities = [o for o in longopts if o.startswith(opt)]
    if not possibilities:
Tim Peters's avatar
Tim Peters committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
        raise GetoptError('option --%s not recognized' % opt, opt)
    # Is there an exact match?
    if opt in possibilities:
        return 0, opt
    elif opt + '=' in possibilities:
        return 1, opt
    # No exact match, so better be unique.
    if len(possibilities) > 1:
        # XXX since possibilities contains all valid continuations, might be
        # nice to work them into the error msg
        raise GetoptError('option --%s not a unique prefix' % opt, opt)
    assert len(possibilities) == 1
    unique_match = possibilities[0]
    has_arg = unique_match.endswith('=')
    if has_arg:
        unique_match = unique_match[:-1]
    return has_arg, unique_match
120

121
def do_shorts(opts, optstring, shortopts, args):
Guido van Rossum's avatar
Guido van Rossum committed
122
    while optstring != '':
123 124 125 126
        opt, optstring = optstring[0], optstring[1:]
        if short_has_arg(opt, shortopts):
            if optstring == '':
                if not args:
Fred Drake's avatar
Fred Drake committed
127 128
                    raise GetoptError('option -%s requires argument' % opt,
                                      opt)
129 130 131 132
                optstring, args = args[0], args[1:]
            optarg, optstring = optstring, ''
        else:
            optarg = ''
133 134
        opts.append(('-' + opt, optarg))
    return opts, args
135 136

def short_has_arg(opt, shortopts):
Guido van Rossum's avatar
Guido van Rossum committed
137
    for i in range(len(shortopts)):
138
        if opt == shortopts[i] != ':':
Fred Drake's avatar
Fred Drake committed
139
            return shortopts.startswith(':', i+1)
140
    raise GetoptError('option -%s not recognized' % opt, opt)
141 142

if __name__ == '__main__':
Guido van Rossum's avatar
Guido van Rossum committed
143 144
    import sys
    print getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])