Home | History | Annotate | Download | only in Lib
      1 """Parser for command line options.
      2 
      3 This module helps scripts to parse the command line arguments in
      4 sys.argv.  It supports the same conventions as the Unix getopt()
      5 function (including the special meanings of arguments of the form `-'
      6 and `--').  Long options similar to those supported by GNU software
      7 may be used as well via an optional third argument.  This module
      8 provides two functions and an exception:
      9 
     10 getopt() -- Parse command line options
     11 gnu_getopt() -- Like getopt(), but allow option and non-option arguments
     12 to be intermixed.
     13 GetoptError -- exception (class) raised with 'opt' attribute, which is the
     14 option involved with the exception.
     15 """
     16 
     17 # Long option support added by Lars Wirzenius <liw (at] iki.fi>.
     18 #
     19 # Gerrit Holl <gerrit (at] nl.linux.org> moved the string-based exceptions
     20 # to class-based exceptions.
     21 #
     22 # Peter Astrand <astrand (at] lysator.liu.se> added gnu_getopt().
     23 #
     24 # TODO for gnu_getopt():
     25 #
     26 # - GNU getopt_long_only mechanism
     27 # - allow the caller to specify ordering
     28 # - RETURN_IN_ORDER option
     29 # - GNU extension with '-' as first character of option string
     30 # - optional arguments, specified by double colons
     31 # - a option string with a W followed by semicolon should
     32 #   treat "-W foo" as "--foo"
     33 
     34 __all__ = ["GetoptError","error","getopt","gnu_getopt"]
     35 
     36 import os
     37 
     38 class GetoptError(Exception):
     39     opt = ''
     40     msg = ''
     41     def __init__(self, msg, opt=''):
     42         self.msg = msg
     43         self.opt = opt
     44         Exception.__init__(self, msg, opt)
     45 
     46     def __str__(self):
     47         return self.msg
     48 
     49 error = GetoptError # backward compatibility
     50 
     51 def getopt(args, shortopts, longopts = []):
     52     """getopt(args, options[, long_options]) -> opts, args
     53 
     54     Parses command line options and parameter list.  args is the
     55     argument list to be parsed, without the leading reference to the
     56     running program.  Typically, this means "sys.argv[1:]".  shortopts
     57     is the string of option letters that the script wants to
     58     recognize, with options that require an argument followed by a
     59     colon (i.e., the same format that Unix getopt() uses).  If
     60     specified, longopts is a list of strings with the names of the
     61     long options which should be supported.  The leading '--'
     62     characters should not be included in the option name.  Options
     63     which require an argument should be followed by an equal sign
     64     ('=').
     65 
     66     The return value consists of two elements: the first is a list of
     67     (option, value) pairs; the second is the list of program arguments
     68     left after the option list was stripped (this is a trailing slice
     69     of the first argument).  Each option-and-value pair returned has
     70     the option as its first element, prefixed with a hyphen (e.g.,
     71     '-x'), and the option argument as its second element, or an empty
     72     string if the option has no argument.  The options occur in the
     73     list in the same order in which they were found, thus allowing
     74     multiple occurrences.  Long and short options may be mixed.
     75 
     76     """
     77 
     78     opts = []
     79     if type(longopts) == type(""):
     80         longopts = [longopts]
     81     else:
     82         longopts = list(longopts)
     83     while args and args[0].startswith('-') and args[0] != '-':
     84         if args[0] == '--':
     85             args = args[1:]
     86             break
     87         if args[0].startswith('--'):
     88             opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
     89         else:
     90             opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
     91 
     92     return opts, args
     93 
     94 def gnu_getopt(args, shortopts, longopts = []):
     95     """getopt(args, options[, long_options]) -> opts, args
     96 
     97     This function works like getopt(), except that GNU style scanning
     98     mode is used by default. This means that option and non-option
     99     arguments may be intermixed. The getopt() function stops
    100     processing options as soon as a non-option argument is
    101     encountered.
    102 
    103     If the first character of the option string is `+', or if the
    104     environment variable POSIXLY_CORRECT is set, then option
    105     processing stops as soon as a non-option argument is encountered.
    106 
    107     """
    108 
    109     opts = []
    110     prog_args = []
    111     if isinstance(longopts, str):
    112         longopts = [longopts]
    113     else:
    114         longopts = list(longopts)
    115 
    116     # Allow options after non-option arguments?

    117     if shortopts.startswith('+'):
    118         shortopts = shortopts[1:]
    119         all_options_first = True
    120     elif os.environ.get("POSIXLY_CORRECT"):
    121         all_options_first = True
    122     else:
    123         all_options_first = False
    124 
    125     while args:
    126         if args[0] == '--':
    127             prog_args += args[1:]
    128             break
    129 
    130         if args[0][:2] == '--':
    131             opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
    132         elif args[0][:1] == '-' and args[0] != '-':
    133             opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
    134         else:
    135             if all_options_first:
    136                 prog_args += args
    137                 break
    138             else:
    139                 prog_args.append(args[0])
    140                 args = args[1:]
    141 
    142     return opts, prog_args
    143 
    144 def do_longs(opts, opt, longopts, args):
    145     try:
    146         i = opt.index('=')
    147     except ValueError:
    148         optarg = None
    149     else:
    150         opt, optarg = opt[:i], opt[i+1:]
    151 
    152     has_arg, opt = long_has_args(opt, longopts)
    153     if has_arg:
    154         if optarg is None:
    155             if not args:
    156                 raise GetoptError('option --%s requires argument' % opt, opt)
    157             optarg, args = args[0], args[1:]
    158     elif optarg is not None:
    159         raise GetoptError('option --%s must not have an argument' % opt, opt)
    160     opts.append(('--' + opt, optarg or ''))
    161     return opts, args
    162 
    163 # Return:

    164 #   has_arg?

    165 #   full option name

    166 def long_has_args(opt, longopts):
    167     possibilities = [o for o in longopts if o.startswith(opt)]
    168     if not possibilities:
    169         raise GetoptError('option --%s not recognized' % opt, opt)
    170     # Is there an exact match?

    171     if opt in possibilities:
    172         return False, opt
    173     elif opt + '=' in possibilities:
    174         return True, opt
    175     # No exact match, so better be unique.

    176     if len(possibilities) > 1:
    177         # XXX since possibilities contains all valid continuations, might be

    178         # nice to work them into the error msg

    179         raise GetoptError('option --%s not a unique prefix' % opt, opt)
    180     assert len(possibilities) == 1
    181     unique_match = possibilities[0]
    182     has_arg = unique_match.endswith('=')
    183     if has_arg:
    184         unique_match = unique_match[:-1]
    185     return has_arg, unique_match
    186 
    187 def do_shorts(opts, optstring, shortopts, args):
    188     while optstring != '':
    189         opt, optstring = optstring[0], optstring[1:]
    190         if short_has_arg(opt, shortopts):
    191             if optstring == '':
    192                 if not args:
    193                     raise GetoptError('option -%s requires argument' % opt,
    194                                       opt)
    195                 optstring, args = args[0], args[1:]
    196             optarg, optstring = optstring, ''
    197         else:
    198             optarg = ''
    199         opts.append(('-' + opt, optarg))
    200     return opts, args
    201 
    202 def short_has_arg(opt, shortopts):
    203     for i in range(len(shortopts)):
    204         if opt == shortopts[i] != ':':
    205             return shortopts.startswith(':', i+1)
    206     raise GetoptError('option -%s not recognized' % opt, opt)
    207 
    208 if __name__ == '__main__':
    209     import sys
    210     print getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])
    211