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