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