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