1 # -*- coding: utf-8 -*-
3 """Parser for command line options.
5 This module helps scripts to parse the command line arguments in
6 sys.argv. It supports the same conventions as the Unix getopt()
7 function (including the special meanings of arguments of the form `-'
8 and `--'). Long options similar to those supported by GNU software
9 may be used as well via an optional third argument. This module
10 provides two functions and an exception:
12 getopt() -- Parse command line options
13 gnu_getopt() -- Like getopt(), but allow option and non-option arguments
15 GetoptError -- exception (class) raised with 'opt' attribute, which is the
16 option involved with the exception.
19 # Long option support added by Lars Wirzenius <liw@iki.fi>.
21 # Gerrit Holl <gerrit@nl.linux.org> moved the string-based exceptions
22 # to class-based exceptions.
24 # Peter Åstrand <astrand@lysator.liu.se> added gnu_getopt().
26 # TODO for gnu_getopt():
28 # - GNU getopt_long_only mechanism
29 # - allow the caller to specify ordering
30 # - RETURN_IN_ORDER option
31 # - GNU extension with '-' as first character of option string
32 # - optional arguments, specified by double colons
33 # - an option string with a W followed by semicolon should
34 # treat "-W foo" as "--foo"
36 __all__ = ["GetoptError","error","getopt","gnu_getopt"]
40 from gettext import gettext as _
42 # Bootstrapping Python: gettext's dependencies not built yet
45 class GetoptError(Exception):
48 def __init__(self, msg, opt=''):
51 Exception.__init__(self, msg, opt)
56 error = GetoptError # backward compatibility
58 def getopt(args, shortopts, longopts = []):
59 """getopt(args, options[, long_options]) -> opts, args
61 Parses command line options and parameter list. args is the
62 argument list to be parsed, without the leading reference to the
63 running program. Typically, this means "sys.argv[1:]". shortopts
64 is the string of option letters that the script wants to
65 recognize, with options that require an argument followed by a
66 colon (i.e., the same format that Unix getopt() uses). If
67 specified, longopts is a list of strings with the names of the
68 long options which should be supported. The leading '--'
69 characters should not be included in the option name. Options
70 which require an argument should be followed by an equal sign
73 The return value consists of two elements: the first is a list of
74 (option, value) pairs; the second is the list of program arguments
75 left after the option list was stripped (this is a trailing slice
76 of the first argument). Each option-and-value pair returned has
77 the option as its first element, prefixed with a hyphen (e.g.,
78 '-x'), and the option argument as its second element, or an empty
79 string if the option has no argument. The options occur in the
80 list in the same order in which they were found, thus allowing
81 multiple occurrences. Long and short options may be mixed.
86 if type(longopts) == type(""):
89 longopts = list(longopts)
90 while args and args[0].startswith(b'-') and args[0] != '-':
94 if args[0].startswith(b'--'):
95 opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
97 opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
101 def gnu_getopt(args, shortopts, longopts = []):
102 """getopt(args, options[, long_options]) -> opts, args
104 This function works like getopt(), except that GNU style scanning
105 mode is used by default. This means that option and non-option
106 arguments may be intermixed. The getopt() function stops
107 processing options as soon as a non-option argument is
110 If the first character of the option string is `+', or if the
111 environment variable POSIXLY_CORRECT is set, then option
112 processing stops as soon as a non-option argument is encountered.
118 if isinstance(longopts, str):
119 longopts = [longopts]
121 longopts = list(longopts)
123 # Allow options after non-option arguments?
124 if shortopts.startswith(b'+'):
125 shortopts = shortopts[1:]
126 all_options_first = True
127 elif os.environ.get("POSIXLY_CORRECT"):
128 all_options_first = True
130 all_options_first = False
134 prog_args += args[1:]
137 if args[0][:2] == '--':
138 opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
139 elif args[0][:1] == '-' and args[0] != '-':
140 opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
142 if all_options_first:
146 prog_args.append(args[0])
149 return opts, prog_args
151 def do_longs(opts, opt, longopts, args):
157 opt, optarg = opt[:i], opt[i+1:]
159 has_arg, opt = long_has_args(opt, longopts)
163 raise GetoptError(_('option --%s requires argument') % opt, opt)
164 optarg, args = args[0], args[1:]
165 elif optarg is not None:
166 raise GetoptError(_('option --%s must not have an argument') % opt, opt)
167 opts.append(('--' + opt, optarg or ''))
173 def long_has_args(opt, longopts):
174 possibilities = [o for o in longopts if o.startswith(opt)]
175 if not possibilities:
176 raise GetoptError(_('option --%s not recognized') % opt, opt)
177 # Is there an exact match?
178 if opt in possibilities:
180 elif opt + '=' in possibilities:
182 # No exact match, so better be unique.
183 if len(possibilities) > 1:
184 # XXX since possibilities contains all valid continuations, might be
185 # nice to work them into the error msg
186 raise GetoptError(_('option --%s not a unique prefix') % opt, opt)
187 assert len(possibilities) == 1
188 unique_match = possibilities[0]
189 has_arg = unique_match.endswith('=')
191 unique_match = unique_match[:-1]
192 return has_arg, unique_match
194 def do_shorts(opts, optstring, shortopts, args):
195 while optstring != '':
196 opt, optstring = optstring[0], optstring[1:]
197 if short_has_arg(opt, shortopts):
200 raise GetoptError(_('option -%s requires argument') % opt,
202 optstring, args = args[0], args[1:]
203 optarg, optstring = optstring, ''
206 opts.append(('-' + opt, optarg))
209 def short_has_arg(opt, shortopts):
210 for i in range(len(shortopts)):
211 if opt == shortopts[i] != ':':
212 return shortopts.startswith(b':', i+1)
213 raise GetoptError(_('option -%s not recognized') % opt, opt)
215 if __name__ == '__main__':
217 print(getopt(sys.argv[1:], "a:b", ["alpha=", "beta"]))