1 # -*- coding: utf-8 -*-
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
14 GetoptError -- exception (class) raised with 'opt' attribute, which is the
15 option involved with the exception.
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"]
39 class GetoptError(Exception):
42 def __init__(self
, msg
, opt
=''):
45 Exception.__init
__(self
, msg
, opt
)
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
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.
80 if type(longopts
) == type(""):
83 longopts
= list(longopts
)
84 while args
and args
[0].startswith('-') and args
[0] != '-':
88 if args
[0].startswith('--'):
89 opts
, args
= do_longs(opts
, args
[0][2:], longopts
, args
[1:])
91 opts
, args
= do_shorts(opts
, args
[0][1:], shortopts
, args
[1:])
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
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.
112 if isinstance(longopts
, str):
113 longopts
= [longopts
]
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
124 all_options_first
= False
128 prog_args
+= args
[1:]
131 if args
[0][:2] == '--':
132 opts
, args
= do_longs(opts
, args
[0][2:], longopts
, args
[1:])
133 elif args
[0][:1] == '-' and args
[0] != '-':
134 opts
, args
= do_shorts(opts
, args
[0][1:], shortopts
, args
[1:])
136 if all_options_first
:
140 prog_args
.append(args
[0])
143 return opts
, prog_args
145 def do_longs(opts
, opt
, longopts
, args
):
151 opt
, optarg
= opt
[:i
], opt
[i
+1:]
153 has_arg
, opt
= long_has_args(opt
, longopts
)
157 raise GetoptError('option --%s requires argument' % opt
, opt
)
158 optarg
, args
= args
[0], args
[1:]
160 raise GetoptError('option --%s must not have an argument' % opt
, opt
)
161 opts
.append(('--' + opt
, optarg
or ''))
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
:
174 elif opt
+ '=' in possibilities
:
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('=')
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
):
194 raise GetoptError('option -%s requires argument' % opt
,
196 optstring
, args
= args
[0], args
[1:]
197 optarg
, optstring
= optstring
, ''
200 opts
.append(('-' + opt
, optarg
))
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__':
211 print(getopt(sys
.argv
[1:], "a:b", ["alpha=", "beta"]))