1"""Parser for command line options. 2 3This module helps scripts to parse the command line arguments in 4sys.argv. It supports the same conventions as the Unix getopt() 5function (including the special meanings of arguments of the form `-' 6and `--'). Long options similar to those supported by GNU software 7may be used as well via an optional third argument. This module 8provides two functions and an exception: 9 10getopt() -- Parse command line options 11gnu_getopt() -- Like getopt(), but allow option and non-option arguments 12to be intermixed. 13GetoptError -- exception (class) raised with 'opt' attribute, which is the 14option involved with the exception. 15""" 16 17# Long option support added by Lars Wirzenius <liw@iki.fi>. 18# 19# Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions 20# to class-based exceptions. 21# 22# Peter Åstrand <astrand@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# - an option string with a W followed by semicolon should 32# treat "-W foo" as "--foo" 33 34__all__ = ["GetoptError","error","getopt","gnu_getopt"] 35 36import os 37try: 38 from gettext import gettext as _ 39except ImportError: 40 # Bootstrapping Python: gettext's dependencies not built yet 41 def _(s): return s 42 43class GetoptError(Exception): 44 opt = '' 45 msg = '' 46 def __init__(self, msg, opt=''): 47 self.msg = msg 48 self.opt = opt 49 Exception.__init__(self, msg, opt) 50 51 def __str__(self): 52 return self.msg 53 54error = GetoptError # backward compatibility 55 56def getopt(args, shortopts, longopts = []): 57 """getopt(args, options[, long_options]) -> opts, args 58 59 Parses command line options and parameter list. args is the 60 argument list to be parsed, without the leading reference to the 61 running program. Typically, this means "sys.argv[1:]". shortopts 62 is the string of option letters that the script wants to 63 recognize, with options that require an argument followed by a 64 colon (i.e., the same format that Unix getopt() uses). If 65 specified, longopts is a list of strings with the names of the 66 long options which should be supported. The leading '--' 67 characters should not be included in the option name. Options 68 which require an argument should be followed by an equal sign 69 ('='). 70 71 The return value consists of two elements: the first is a list of 72 (option, value) pairs; the second is the list of program arguments 73 left after the option list was stripped (this is a trailing slice 74 of the first argument). Each option-and-value pair returned has 75 the option as its first element, prefixed with a hyphen (e.g., 76 '-x'), and the option argument as its second element, or an empty 77 string if the option has no argument. The options occur in the 78 list in the same order in which they were found, thus allowing 79 multiple occurrences. Long and short options may be mixed. 80 81 """ 82 83 opts = [] 84 if type(longopts) == type(""): 85 longopts = [longopts] 86 else: 87 longopts = list(longopts) 88 while args and args[0].startswith('-') and args[0] != '-': 89 if args[0] == '--': 90 args = args[1:] 91 break 92 if args[0].startswith('--'): 93 opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) 94 else: 95 opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) 96 97 return opts, args 98 99def gnu_getopt(args, shortopts, longopts = []): 100 """getopt(args, options[, long_options]) -> opts, args 101 102 This function works like getopt(), except that GNU style scanning 103 mode is used by default. This means that option and non-option 104 arguments may be intermixed. The getopt() function stops 105 processing options as soon as a non-option argument is 106 encountered. 107 108 If the first character of the option string is `+', or if the 109 environment variable POSIXLY_CORRECT is set, then option 110 processing stops as soon as a non-option argument is encountered. 111 112 """ 113 114 opts = [] 115 prog_args = [] 116 if isinstance(longopts, str): 117 longopts = [longopts] 118 else: 119 longopts = list(longopts) 120 121 # Allow options after non-option arguments? 122 if shortopts.startswith('+'): 123 shortopts = shortopts[1:] 124 all_options_first = True 125 elif os.environ.get("POSIXLY_CORRECT"): 126 all_options_first = True 127 else: 128 all_options_first = False 129 130 while args: 131 if args[0] == '--': 132 prog_args += args[1:] 133 break 134 135 if args[0][:2] == '--': 136 opts, args = do_longs(opts, args[0][2:], longopts, args[1:]) 137 elif args[0][:1] == '-' and args[0] != '-': 138 opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:]) 139 else: 140 if all_options_first: 141 prog_args += args 142 break 143 else: 144 prog_args.append(args[0]) 145 args = args[1:] 146 147 return opts, prog_args 148 149def do_longs(opts, opt, longopts, args): 150 try: 151 i = opt.index('=') 152 except ValueError: 153 optarg = None 154 else: 155 opt, optarg = opt[:i], opt[i+1:] 156 157 has_arg, opt = long_has_args(opt, longopts) 158 if has_arg: 159 if optarg is None: 160 if not args: 161 raise GetoptError(_('option --%s requires argument') % opt, opt) 162 optarg, args = args[0], args[1:] 163 elif optarg is not None: 164 raise GetoptError(_('option --%s must not have an argument') % opt, opt) 165 opts.append(('--' + opt, optarg or '')) 166 return opts, args 167 168# Return: 169# has_arg? 170# full option name 171def long_has_args(opt, longopts): 172 possibilities = [o for o in longopts if o.startswith(opt)] 173 if not possibilities: 174 raise GetoptError(_('option --%s not recognized') % opt, opt) 175 # Is there an exact match? 176 if opt in possibilities: 177 return False, opt 178 elif opt + '=' in possibilities: 179 return True, opt 180 # No exact match, so better be unique. 181 if len(possibilities) > 1: 182 # XXX since possibilities contains all valid continuations, might be 183 # nice to work them into the error msg 184 raise GetoptError(_('option --%s not a unique prefix') % opt, opt) 185 assert len(possibilities) == 1 186 unique_match = possibilities[0] 187 has_arg = unique_match.endswith('=') 188 if has_arg: 189 unique_match = unique_match[:-1] 190 return has_arg, unique_match 191 192def do_shorts(opts, optstring, shortopts, args): 193 while optstring != '': 194 opt, optstring = optstring[0], optstring[1:] 195 if short_has_arg(opt, shortopts): 196 if optstring == '': 197 if not args: 198 raise GetoptError(_('option -%s requires argument') % opt, 199 opt) 200 optstring, args = args[0], args[1:] 201 optarg, optstring = optstring, '' 202 else: 203 optarg = '' 204 opts.append(('-' + opt, optarg)) 205 return opts, args 206 207def short_has_arg(opt, shortopts): 208 for i in range(len(shortopts)): 209 if opt == shortopts[i] != ':': 210 return shortopts.startswith(':', i+1) 211 raise GetoptError(_('option -%s not recognized') % opt, opt) 212 213if __name__ == '__main__': 214 import sys 215 print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"])) 216