1
|
1 |
"""optik.option_parser
|
|
2 |
|
|
3 |
Provides the OptionParser and Values classes.
|
|
4 |
"""
|
|
5 |
|
|
6 |
# Copyright (c) 2001-2004 Gregory P. Ward. All rights reserved.
|
|
7 |
# See the README.txt distributed with Optik for licensing terms.
|
|
8 |
|
|
9 |
import sys, os
|
|
10 |
import types, string
|
|
11 |
from optik.option import Option, NO_DEFAULT, _repr
|
|
12 |
from optik.help import IndentedHelpFormatter
|
|
13 |
from optik import errors
|
|
14 |
from optik.errors import gettext
|
|
15 |
_ = gettext
|
|
16 |
|
|
17 |
__revision__ = "$Id: option_parser.py,v 1.1 2009/02/05 23:03:30 stechong Exp $"
|
|
18 |
|
|
19 |
__all__ = ['SUPPRESS_HELP', 'SUPPRESS_USAGE',
|
|
20 |
'Values', 'OptionContainer', 'OptionGroup', 'OptionParser']
|
|
21 |
|
|
22 |
|
|
23 |
SUPPRESS_HELP = "SUPPRESS"+"HELP"
|
|
24 |
SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
|
|
25 |
|
|
26 |
# For compatibility with Python 2.2
|
|
27 |
try:
|
|
28 |
True, False
|
|
29 |
except NameError:
|
|
30 |
(True, False) = (1, 0)
|
|
31 |
def isbasestring(x):
|
|
32 |
return isinstance(x, types.StringType) or isinstance(x, types.UnicodeType)
|
|
33 |
if not hasattr(string, "startswith"):
|
|
34 |
def startswith(s, prefix):
|
|
35 |
return s[:len(prefix)] == prefix
|
|
36 |
string.startswith = startswith
|
|
37 |
|
|
38 |
class Values:
|
|
39 |
|
|
40 |
def __init__(self, defaults=None):
|
|
41 |
if defaults:
|
|
42 |
for (attr, val) in defaults.items():
|
|
43 |
setattr(self, attr, val)
|
|
44 |
|
|
45 |
def __str__(self):
|
|
46 |
return str(self.__dict__)
|
|
47 |
|
|
48 |
__repr__ = _repr
|
|
49 |
|
|
50 |
def __cmp__(self, other):
|
|
51 |
if isinstance(other, Values):
|
|
52 |
return cmp(self.__dict__, other.__dict__)
|
|
53 |
elif isinstance(other, types.DictType):
|
|
54 |
return cmp(self.__dict__, other)
|
|
55 |
else:
|
|
56 |
return -1
|
|
57 |
|
|
58 |
def _update_careful(self, dict):
|
|
59 |
"""
|
|
60 |
Update the option values from an arbitrary dictionary, but only
|
|
61 |
use keys from dict that already have a corresponding attribute
|
|
62 |
in self. Any keys in dict without a corresponding attribute
|
|
63 |
are silently ignored.
|
|
64 |
"""
|
|
65 |
for attr in dir(self):
|
|
66 |
if dict.has_key(attr):
|
|
67 |
dval = dict[attr]
|
|
68 |
if dval is not None:
|
|
69 |
setattr(self, attr, dval)
|
|
70 |
|
|
71 |
def _update_loose(self, dict):
|
|
72 |
"""
|
|
73 |
Update the option values from an arbitrary dictionary,
|
|
74 |
using all keys from the dictionary regardless of whether
|
|
75 |
they have a corresponding attribute in self or not.
|
|
76 |
"""
|
|
77 |
self.__dict__.update(dict)
|
|
78 |
|
|
79 |
def _update(self, dict, mode):
|
|
80 |
if mode == "careful":
|
|
81 |
self._update_careful(dict)
|
|
82 |
elif mode == "loose":
|
|
83 |
self._update_loose(dict)
|
|
84 |
else:
|
|
85 |
raise ValueError, "invalid update mode: %s" % repr(mode)
|
|
86 |
|
|
87 |
def read_module(self, modname, mode="careful"):
|
|
88 |
__import__(modname)
|
|
89 |
mod = sys.modules[modname]
|
|
90 |
self._update(vars(mod), mode)
|
|
91 |
|
|
92 |
def read_file(self, filename, mode="careful"):
|
|
93 |
vars = {}
|
|
94 |
execfile(filename, vars)
|
|
95 |
self._update(vars, mode)
|
|
96 |
|
|
97 |
def ensure_value(self, attr, value):
|
|
98 |
if not hasattr(self, attr) or getattr(self, attr) is None:
|
|
99 |
setattr(self, attr, value)
|
|
100 |
return getattr(self, attr)
|
|
101 |
|
|
102 |
|
|
103 |
class OptionContainer:
|
|
104 |
|
|
105 |
"""
|
|
106 |
Abstract base class.
|
|
107 |
|
|
108 |
Class attributes:
|
|
109 |
standard_option_list : [Option]
|
|
110 |
list of standard options that will be accepted by all instances
|
|
111 |
of this parser class (intended to be overridden by subclasses).
|
|
112 |
|
|
113 |
Instance attributes:
|
|
114 |
option_list : [Option]
|
|
115 |
the list of Option objects contained by this OptionContainer
|
|
116 |
_short_opt : { string : Option }
|
|
117 |
dictionary mapping short option strings, eg. "-f" or "-X",
|
|
118 |
to the Option instances that implement them. If an Option
|
|
119 |
has multiple short option strings, it will appears in this
|
|
120 |
dictionary multiple times. [1]
|
|
121 |
_long_opt : { string : Option }
|
|
122 |
dictionary mapping long option strings, eg. "--file" or
|
|
123 |
"--exclude", to the Option instances that implement them.
|
|
124 |
Again, a given Option can occur multiple times in this
|
|
125 |
dictionary. [1]
|
|
126 |
defaults : { string : any }
|
|
127 |
dictionary mapping option destination names to default
|
|
128 |
values for each destination [1]
|
|
129 |
|
|
130 |
[1] These mappings are common to (shared by) all components of the
|
|
131 |
controlling OptionParser, where they are initially created.
|
|
132 |
|
|
133 |
"""
|
|
134 |
|
|
135 |
def __init__(self, option_class, conflict_handler, description):
|
|
136 |
# Initialize the option list and related data structures.
|
|
137 |
# This method must be provided by subclasses, and it must
|
|
138 |
# initialize at least the following instance attributes:
|
|
139 |
# option_list, _short_opt, _long_opt, defaults.
|
|
140 |
self._create_option_list()
|
|
141 |
|
|
142 |
self.option_class = option_class
|
|
143 |
self.set_conflict_handler(conflict_handler)
|
|
144 |
self.set_description(description)
|
|
145 |
|
|
146 |
def _create_option_mappings(self):
|
|
147 |
# For use by OptionParser constructor -- create the master
|
|
148 |
# option mappings used by this OptionParser and all
|
|
149 |
# OptionGroups that it owns.
|
|
150 |
self._short_opt = {} # single letter -> Option instance
|
|
151 |
self._long_opt = {} # long option -> Option instance
|
|
152 |
self.defaults = {} # maps option dest -> default value
|
|
153 |
|
|
154 |
|
|
155 |
def _share_option_mappings(self, parser):
|
|
156 |
# For use by OptionGroup constructor -- use shared option
|
|
157 |
# mappings from the OptionParser that owns this OptionGroup.
|
|
158 |
self._short_opt = parser._short_opt
|
|
159 |
self._long_opt = parser._long_opt
|
|
160 |
self.defaults = parser.defaults
|
|
161 |
|
|
162 |
def set_conflict_handler(self, handler):
|
|
163 |
if handler not in ("error", "resolve"):
|
|
164 |
raise ValueError, "invalid conflict_resolution value %s" % repr(handler)
|
|
165 |
self.conflict_handler = handler
|
|
166 |
|
|
167 |
def set_description(self, description):
|
|
168 |
self.description = description
|
|
169 |
|
|
170 |
def get_description(self):
|
|
171 |
return self.description
|
|
172 |
|
|
173 |
|
|
174 |
# -- Option-adding methods -----------------------------------------
|
|
175 |
|
|
176 |
def _check_conflict(self, option):
|
|
177 |
conflict_opts = []
|
|
178 |
for opt in option._short_opts:
|
|
179 |
if self._short_opt.has_key(opt):
|
|
180 |
conflict_opts.append((opt, self._short_opt[opt]))
|
|
181 |
for opt in option._long_opts:
|
|
182 |
if self._long_opt.has_key(opt):
|
|
183 |
conflict_opts.append((opt, self._long_opt[opt]))
|
|
184 |
|
|
185 |
if conflict_opts:
|
|
186 |
handler = self.conflict_handler
|
|
187 |
if handler == "error":
|
|
188 |
opts = []
|
|
189 |
for co in conflict_opts:
|
|
190 |
opts.append(co[0])
|
|
191 |
raise errors.OptionConflictError(
|
|
192 |
"conflicting option string(s): %s"
|
|
193 |
% string.join(opts, ", "),
|
|
194 |
option)
|
|
195 |
elif handler == "resolve":
|
|
196 |
for (opt, c_option) in conflict_opts:
|
|
197 |
if string.startswith(opt, "--"):
|
|
198 |
c_option._long_opts.remove(opt)
|
|
199 |
del self._long_opt[opt]
|
|
200 |
else:
|
|
201 |
c_option._short_opts.remove(opt)
|
|
202 |
del self._short_opt[opt]
|
|
203 |
if not (c_option._short_opts or c_option._long_opts):
|
|
204 |
c_option.container.option_list.remove(c_option)
|
|
205 |
|
|
206 |
def add_option(self, *args, **kwargs):
|
|
207 |
"""add_option(Option)
|
|
208 |
add_option(opt_str, ..., kwarg=val, ...)
|
|
209 |
"""
|
|
210 |
if type(args[0]) is types.StringType:
|
|
211 |
option = apply(self.option_class, args, kwargs)
|
|
212 |
elif len(args) == 1 and not kwargs:
|
|
213 |
option = args[0]
|
|
214 |
if not isinstance(option, Option):
|
|
215 |
raise TypeError, "not an Option instance: %s" % repr(option)
|
|
216 |
else:
|
|
217 |
raise TypeError, "invalid arguments"
|
|
218 |
|
|
219 |
self._check_conflict(option)
|
|
220 |
|
|
221 |
self.option_list.append(option)
|
|
222 |
option.container = self
|
|
223 |
for opt in option._short_opts:
|
|
224 |
self._short_opt[opt] = option
|
|
225 |
for opt in option._long_opts:
|
|
226 |
self._long_opt[opt] = option
|
|
227 |
|
|
228 |
if option.dest is not None: # option has a dest, we need a default
|
|
229 |
if option.default is not NO_DEFAULT:
|
|
230 |
self.defaults[option.dest] = option.default
|
|
231 |
elif not self.defaults.has_key(option.dest):
|
|
232 |
self.defaults[option.dest] = None
|
|
233 |
|
|
234 |
return option
|
|
235 |
|
|
236 |
def add_options(self, option_list):
|
|
237 |
for option in option_list:
|
|
238 |
self.add_option(option)
|
|
239 |
|
|
240 |
# -- Option query/removal methods ----------------------------------
|
|
241 |
|
|
242 |
def get_option(self, opt_str):
|
|
243 |
return (self._short_opt.get(opt_str) or
|
|
244 |
self._long_opt.get(opt_str))
|
|
245 |
|
|
246 |
def has_option(self, opt_str):
|
|
247 |
return (self._short_opt.has_key(opt_str) or
|
|
248 |
self._long_opt.has_key(opt_str))
|
|
249 |
|
|
250 |
def remove_option(self, opt_str):
|
|
251 |
option = self._short_opt.get(opt_str)
|
|
252 |
if option is None:
|
|
253 |
option = self._long_opt.get(opt_str)
|
|
254 |
if option is None:
|
|
255 |
raise ValueError("no such option %s" % repr(opt_str))
|
|
256 |
|
|
257 |
for opt in option._short_opts:
|
|
258 |
del self._short_opt[opt]
|
|
259 |
for opt in option._long_opts:
|
|
260 |
del self._long_opt[opt]
|
|
261 |
option.container.option_list.remove(option)
|
|
262 |
|
|
263 |
|
|
264 |
# -- Help-formatting methods ---------------------------------------
|
|
265 |
|
|
266 |
def format_option_help(self, formatter):
|
|
267 |
if not self.option_list:
|
|
268 |
return ""
|
|
269 |
result = []
|
|
270 |
for option in self.option_list:
|
|
271 |
if not option.help is SUPPRESS_HELP:
|
|
272 |
result.append(formatter.format_option(option))
|
|
273 |
return string.join(result, "")
|
|
274 |
|
|
275 |
def format_description(self, formatter):
|
|
276 |
return formatter.format_description(self.get_description())
|
|
277 |
|
|
278 |
def format_help(self, formatter):
|
|
279 |
result = []
|
|
280 |
if self.description:
|
|
281 |
result.append(self.format_description(formatter))
|
|
282 |
if self.option_list:
|
|
283 |
result.append(self.format_option_help(formatter))
|
|
284 |
return string.join(result, "\n")
|
|
285 |
|
|
286 |
|
|
287 |
class OptionGroup (OptionContainer):
|
|
288 |
|
|
289 |
def __init__(self, parser, title, description=None):
|
|
290 |
self.parser = parser
|
|
291 |
OptionContainer.__init__(
|
|
292 |
self, parser.option_class, parser.conflict_handler, description)
|
|
293 |
self.title = title
|
|
294 |
|
|
295 |
def _create_option_list(self):
|
|
296 |
self.option_list = []
|
|
297 |
self._share_option_mappings(self.parser)
|
|
298 |
|
|
299 |
def set_title(self, title):
|
|
300 |
self.title = title
|
|
301 |
|
|
302 |
# -- Help-formatting methods ---------------------------------------
|
|
303 |
|
|
304 |
def format_help(self, formatter):
|
|
305 |
result = formatter.format_heading(self.title)
|
|
306 |
formatter.indent()
|
|
307 |
result = result + OptionContainer.format_help(self, formatter)
|
|
308 |
formatter.dedent()
|
|
309 |
return result
|
|
310 |
|
|
311 |
|
|
312 |
class OptionParser (OptionContainer):
|
|
313 |
|
|
314 |
"""
|
|
315 |
Class attributes:
|
|
316 |
standard_option_list : [Option]
|
|
317 |
list of standard options that will be accepted by all instances
|
|
318 |
of this parser class (intended to be overridden by subclasses).
|
|
319 |
|
|
320 |
Instance attributes:
|
|
321 |
usage : string
|
|
322 |
a usage string for your program. Before it is displayed
|
|
323 |
to the user, "%prog" will be expanded to the name of
|
|
324 |
your program (self.prog or os.path.basename(sys.argv[0])).
|
|
325 |
prog : string
|
|
326 |
the name of the current program (to override
|
|
327 |
os.path.basename(sys.argv[0])).
|
|
328 |
|
|
329 |
option_groups : [OptionGroup]
|
|
330 |
list of option groups in this parser (option groups are
|
|
331 |
irrelevant for parsing the command-line, but very useful
|
|
332 |
for generating help)
|
|
333 |
|
|
334 |
allow_interspersed_args : bool = true
|
|
335 |
if true, positional arguments may be interspersed with options.
|
|
336 |
Assuming -a and -b each take a single argument, the command-line
|
|
337 |
-ablah foo bar -bboo baz
|
|
338 |
will be interpreted the same as
|
|
339 |
-ablah -bboo -- foo bar baz
|
|
340 |
If this flag were false, that command line would be interpreted as
|
|
341 |
-ablah -- foo bar -bboo baz
|
|
342 |
-- ie. we stop processing options as soon as we see the first
|
|
343 |
non-option argument. (This is the tradition followed by
|
|
344 |
Python's getopt module, Perl's Getopt::Std, and other argument-
|
|
345 |
parsing libraries, but it is generally annoying to users.)
|
|
346 |
|
|
347 |
process_default_values : bool = true
|
|
348 |
if true, option default values are processed similarly to option
|
|
349 |
values from the command line: that is, they are passed to the
|
|
350 |
type-checking function for the option's type (as long as the
|
|
351 |
default value is a string). (This really only matters if you
|
|
352 |
have defined custom types; see SF bug #955889.) Set it to false
|
|
353 |
to restore the behaviour of Optik 1.4.1 and earlier.
|
|
354 |
|
|
355 |
rargs : [string]
|
|
356 |
the argument list currently being parsed. Only set when
|
|
357 |
parse_args() is active, and continually trimmed down as
|
|
358 |
we consume arguments. Mainly there for the benefit of
|
|
359 |
callback options.
|
|
360 |
largs : [string]
|
|
361 |
the list of leftover arguments that we have skipped while
|
|
362 |
parsing options. If allow_interspersed_args is false, this
|
|
363 |
list is always empty.
|
|
364 |
values : Values
|
|
365 |
the set of option values currently being accumulated. Only
|
|
366 |
set when parse_args() is active. Also mainly for callbacks.
|
|
367 |
|
|
368 |
Because of the 'rargs', 'largs', and 'values' attributes,
|
|
369 |
OptionParser is not thread-safe. If, for some perverse reason, you
|
|
370 |
need to parse command-line arguments simultaneously in different
|
|
371 |
threads, use different OptionParser instances.
|
|
372 |
|
|
373 |
"""
|
|
374 |
|
|
375 |
standard_option_list = []
|
|
376 |
|
|
377 |
def __init__(self,
|
|
378 |
usage=None,
|
|
379 |
option_list=None,
|
|
380 |
option_class=Option,
|
|
381 |
version=None,
|
|
382 |
conflict_handler="error",
|
|
383 |
description=None,
|
|
384 |
formatter=None,
|
|
385 |
add_help_option=True,
|
|
386 |
prog=None):
|
|
387 |
OptionContainer.__init__(
|
|
388 |
self, option_class, conflict_handler, description)
|
|
389 |
self.set_usage(usage)
|
|
390 |
self.prog = prog
|
|
391 |
self.version = version
|
|
392 |
self.allow_interspersed_args = True
|
|
393 |
self.process_default_values = True
|
|
394 |
if formatter is None:
|
|
395 |
formatter = IndentedHelpFormatter()
|
|
396 |
self.formatter = formatter
|
|
397 |
self.formatter.set_parser(self)
|
|
398 |
|
|
399 |
# Populate the option list; initial sources are the
|
|
400 |
# standard_option_list class attribute, the 'option_list'
|
|
401 |
# argument, and (if applicable) the _add_version_option() and
|
|
402 |
# _add_help_option() methods.
|
|
403 |
self._populate_option_list(option_list,
|
|
404 |
add_help=add_help_option)
|
|
405 |
|
|
406 |
self._init_parsing_state()
|
|
407 |
|
|
408 |
# -- Private methods -----------------------------------------------
|
|
409 |
# (used by our or OptionContainer's constructor)
|
|
410 |
|
|
411 |
def _create_option_list(self):
|
|
412 |
self.option_list = []
|
|
413 |
self.option_groups = []
|
|
414 |
self._create_option_mappings()
|
|
415 |
|
|
416 |
def _add_help_option(self):
|
|
417 |
self.add_option("-h", "--help",
|
|
418 |
action="help",
|
|
419 |
help=_("show this help message and exit"))
|
|
420 |
|
|
421 |
def _add_version_option(self):
|
|
422 |
self.add_option("--version",
|
|
423 |
action="version",
|
|
424 |
help=_("show program's version number and exit"))
|
|
425 |
|
|
426 |
def _populate_option_list(self, option_list, add_help=True):
|
|
427 |
if self.standard_option_list:
|
|
428 |
self.add_options(self.standard_option_list)
|
|
429 |
if option_list:
|
|
430 |
self.add_options(option_list)
|
|
431 |
if self.version:
|
|
432 |
self._add_version_option()
|
|
433 |
if add_help:
|
|
434 |
self._add_help_option()
|
|
435 |
|
|
436 |
def _init_parsing_state(self):
|
|
437 |
# These are set in parse_args() for the convenience of callbacks.
|
|
438 |
self.rargs = None
|
|
439 |
self.largs = None
|
|
440 |
self.values = None
|
|
441 |
|
|
442 |
|
|
443 |
# -- Simple modifier methods ---------------------------------------
|
|
444 |
|
|
445 |
def set_usage(self, usage):
|
|
446 |
if usage is None:
|
|
447 |
self.usage = _("%prog [options]")
|
|
448 |
elif usage is SUPPRESS_USAGE:
|
|
449 |
self.usage = None
|
|
450 |
# For backwards compatibility with Optik 1.3 and earlier.
|
|
451 |
elif string.startswith(usage, "usage:" + " "):
|
|
452 |
self.usage = usage[7:]
|
|
453 |
else:
|
|
454 |
self.usage = usage
|
|
455 |
|
|
456 |
def enable_interspersed_args(self):
|
|
457 |
self.allow_interspersed_args = True
|
|
458 |
|
|
459 |
def disable_interspersed_args(self):
|
|
460 |
self.allow_interspersed_args = False
|
|
461 |
|
|
462 |
def set_process_default_values(self, process):
|
|
463 |
self.process_default_values = process
|
|
464 |
|
|
465 |
def set_default(self, dest, value):
|
|
466 |
self.defaults[dest] = value
|
|
467 |
|
|
468 |
def set_defaults(self, **kwargs):
|
|
469 |
self.defaults.update(kwargs)
|
|
470 |
|
|
471 |
def _get_all_options(self):
|
|
472 |
options = self.option_list[:]
|
|
473 |
for group in self.option_groups:
|
|
474 |
options.extend(group.option_list)
|
|
475 |
return options
|
|
476 |
|
|
477 |
def get_default_values(self):
|
|
478 |
if not self.process_default_values:
|
|
479 |
# Old, pre-Optik 1.5 behaviour.
|
|
480 |
return Values(self.defaults)
|
|
481 |
|
|
482 |
defaults = self.defaults.copy()
|
|
483 |
for option in self._get_all_options():
|
|
484 |
default = defaults.get(option.dest)
|
|
485 |
if isbasestring(default):
|
|
486 |
opt_str = option.get_opt_string()
|
|
487 |
defaults[option.dest] = option.check_value(opt_str, default)
|
|
488 |
|
|
489 |
return Values(defaults)
|
|
490 |
|
|
491 |
|
|
492 |
# -- OptionGroup methods -------------------------------------------
|
|
493 |
|
|
494 |
def add_option_group(self, *args, **kwargs):
|
|
495 |
# XXX lots of overlap with OptionContainer.add_option()
|
|
496 |
if type(args[0]) is types.StringType:
|
|
497 |
group = apply(OptionGroup, (self,) + args, kwargs)
|
|
498 |
elif len(args) == 1 and not kwargs:
|
|
499 |
group = args[0]
|
|
500 |
if not isinstance(group, OptionGroup):
|
|
501 |
raise TypeError, "not an OptionGroup instance: %s" % repr(group)
|
|
502 |
if group.parser is not self:
|
|
503 |
raise ValueError, "invalid OptionGroup (wrong parser)"
|
|
504 |
else:
|
|
505 |
raise TypeError, "invalid arguments"
|
|
506 |
|
|
507 |
self.option_groups.append(group)
|
|
508 |
return group
|
|
509 |
|
|
510 |
def get_option_group(self, opt_str):
|
|
511 |
option = (self._short_opt.get(opt_str) or
|
|
512 |
self._long_opt.get(opt_str))
|
|
513 |
if option and option.container is not self:
|
|
514 |
return option.container
|
|
515 |
return None
|
|
516 |
|
|
517 |
|
|
518 |
# -- Option-parsing methods ----------------------------------------
|
|
519 |
|
|
520 |
def _get_args(self, args):
|
|
521 |
if args is None:
|
|
522 |
return sys.argv[1:]
|
|
523 |
else:
|
|
524 |
return args[:] # don't modify caller's list
|
|
525 |
|
|
526 |
def parse_args(self, args=None, values=None):
|
|
527 |
"""
|
|
528 |
parse_args(args : [string] = sys.argv[1:],
|
|
529 |
values : Values = None)
|
|
530 |
-> (values : Values, args : [string])
|
|
531 |
|
|
532 |
Parse the command-line options found in 'args' (default:
|
|
533 |
sys.argv[1:]). Any errors result in a call to 'error()', which
|
|
534 |
by default prints the usage message to stderr and calls
|
|
535 |
sys.exit() with an error message. On success returns a pair
|
|
536 |
(values, args) where 'values' is an Values instance (with all
|
|
537 |
your option values) and 'args' is the list of arguments left
|
|
538 |
over after parsing options.
|
|
539 |
"""
|
|
540 |
rargs = self._get_args(args)
|
|
541 |
if values is None:
|
|
542 |
values = self.get_default_values()
|
|
543 |
|
|
544 |
# Store the halves of the argument list as attributes for the
|
|
545 |
# convenience of callbacks:
|
|
546 |
# rargs
|
|
547 |
# the rest of the command-line (the "r" stands for
|
|
548 |
# "remaining" or "right-hand")
|
|
549 |
# largs
|
|
550 |
# the leftover arguments -- ie. what's left after removing
|
|
551 |
# options and their arguments (the "l" stands for "leftover"
|
|
552 |
# or "left-hand")
|
|
553 |
self.rargs = rargs
|
|
554 |
self.largs = largs = []
|
|
555 |
self.values = values
|
|
556 |
|
|
557 |
try:
|
|
558 |
stop = self._process_args(largs, rargs, values)
|
|
559 |
except (errors.BadOptionError, errors.OptionValueError), err:
|
|
560 |
self.error(str(err))
|
|
561 |
|
|
562 |
args = largs + rargs
|
|
563 |
return self.check_values(values, args)
|
|
564 |
|
|
565 |
def check_values(self, values, args):
|
|
566 |
"""
|
|
567 |
check_values(values : Values, args : [string])
|
|
568 |
-> (values : Values, args : [string])
|
|
569 |
|
|
570 |
Check that the supplied option values and leftover arguments are
|
|
571 |
valid. Returns the option values and leftover arguments
|
|
572 |
(possibly adjusted, possibly completely new -- whatever you
|
|
573 |
like). Default implementation just returns the passed-in
|
|
574 |
values; subclasses may override as desired.
|
|
575 |
"""
|
|
576 |
return (values, args)
|
|
577 |
|
|
578 |
def _process_args(self, largs, rargs, values):
|
|
579 |
"""_process_args(largs : [string],
|
|
580 |
rargs : [string],
|
|
581 |
values : Values)
|
|
582 |
|
|
583 |
Process command-line arguments and populate 'values', consuming
|
|
584 |
options and arguments from 'rargs'. If 'allow_interspersed_args' is
|
|
585 |
false, stop at the first non-option argument. If true, accumulate any
|
|
586 |
interspersed non-option arguments in 'largs'.
|
|
587 |
"""
|
|
588 |
while rargs:
|
|
589 |
arg = rargs[0]
|
|
590 |
# We handle bare "--" explicitly, and bare "-" is handled by the
|
|
591 |
# standard arg handler since the short arg case ensures that the
|
|
592 |
# len of the opt string is greater than 1.
|
|
593 |
if arg == "--":
|
|
594 |
del rargs[0]
|
|
595 |
return
|
|
596 |
elif arg[0:2] == "--":
|
|
597 |
# process a single long option (possibly with value(s))
|
|
598 |
self._process_long_opt(rargs, values)
|
|
599 |
elif arg[:1] == "-" and len(arg) > 1:
|
|
600 |
# process a cluster of short options (possibly with
|
|
601 |
# value(s) for the last one only)
|
|
602 |
self._process_short_opts(rargs, values)
|
|
603 |
elif self.allow_interspersed_args:
|
|
604 |
largs.append(arg)
|
|
605 |
del rargs[0]
|
|
606 |
else:
|
|
607 |
return # stop now, leave this arg in rargs
|
|
608 |
|
|
609 |
# Say this is the original argument list:
|
|
610 |
# [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)]
|
|
611 |
# ^
|
|
612 |
# (we are about to process arg(i)).
|
|
613 |
#
|
|
614 |
# Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of
|
|
615 |
# [arg0, ..., arg(i-1)] (any options and their arguments will have
|
|
616 |
# been removed from largs).
|
|
617 |
#
|
|
618 |
# The while loop will usually consume 1 or more arguments per pass.
|
|
619 |
# If it consumes 1 (eg. arg is an option that takes no arguments),
|
|
620 |
# then after _process_arg() is done the situation is:
|
|
621 |
#
|
|
622 |
# largs = subset of [arg0, ..., arg(i)]
|
|
623 |
# rargs = [arg(i+1), ..., arg(N-1)]
|
|
624 |
#
|
|
625 |
# If allow_interspersed_args is false, largs will always be
|
|
626 |
# *empty* -- still a subset of [arg0, ..., arg(i-1)], but
|
|
627 |
# not a very interesting subset!
|
|
628 |
|
|
629 |
def _match_long_opt(self, opt):
|
|
630 |
"""_match_long_opt(opt : string) -> string
|
|
631 |
|
|
632 |
Determine which long option string 'opt' matches, ie. which one
|
|
633 |
it is an unambiguous abbrevation for. Raises BadOptionError if
|
|
634 |
'opt' doesn't unambiguously match any long option string.
|
|
635 |
"""
|
|
636 |
return _match_abbrev(opt, self._long_opt)
|
|
637 |
|
|
638 |
def _process_long_opt(self, rargs, values):
|
|
639 |
arg = rargs.pop(0)
|
|
640 |
|
|
641 |
# Value explicitly attached to arg? Pretend it's the next
|
|
642 |
# argument.
|
|
643 |
if "=" in arg:
|
|
644 |
(opt, next_arg) = string.split(arg, "=", 1)
|
|
645 |
rargs.insert(0, next_arg)
|
|
646 |
had_explicit_value = True
|
|
647 |
else:
|
|
648 |
opt = arg
|
|
649 |
had_explicit_value = False
|
|
650 |
|
|
651 |
opt = self._match_long_opt(opt)
|
|
652 |
option = self._long_opt[opt]
|
|
653 |
if option.takes_value():
|
|
654 |
nargs = option.nargs
|
|
655 |
if len(rargs) < nargs:
|
|
656 |
if nargs == 1:
|
|
657 |
self.error(_("%s option requires an argument") % opt)
|
|
658 |
else:
|
|
659 |
self.error(_("%s option requires %d arguments")
|
|
660 |
% (opt, nargs))
|
|
661 |
elif nargs == 1:
|
|
662 |
value = rargs.pop(0)
|
|
663 |
else:
|
|
664 |
value = tuple(rargs[0:nargs])
|
|
665 |
del rargs[0:nargs]
|
|
666 |
|
|
667 |
elif had_explicit_value:
|
|
668 |
self.error(_("%s option does not take a value") % opt)
|
|
669 |
|
|
670 |
else:
|
|
671 |
value = None
|
|
672 |
|
|
673 |
option.process(opt, value, values, self)
|
|
674 |
|
|
675 |
def _process_short_opts(self, rargs, values):
|
|
676 |
arg = rargs.pop(0)
|
|
677 |
stop = False
|
|
678 |
i = 1
|
|
679 |
for ch in arg[1:]:
|
|
680 |
opt = "-" + ch
|
|
681 |
option = self._short_opt.get(opt)
|
|
682 |
i = i+1 # we have consumed a character
|
|
683 |
|
|
684 |
if not option:
|
|
685 |
raise errors.BadOptionError(opt)
|
|
686 |
#self.error(_("no such option: %s") % opt)
|
|
687 |
if option.takes_value():
|
|
688 |
# Any characters left in arg? Pretend they're the
|
|
689 |
# next arg, and stop consuming characters of arg.
|
|
690 |
if i < len(arg):
|
|
691 |
rargs.insert(0, arg[i:])
|
|
692 |
stop = True
|
|
693 |
|
|
694 |
nargs = option.nargs
|
|
695 |
if len(rargs) < nargs:
|
|
696 |
if nargs == 1:
|
|
697 |
self.error(_("%s option requires an argument") % opt)
|
|
698 |
else:
|
|
699 |
self.error(_("%s option requires %d arguments")
|
|
700 |
% (opt, nargs))
|
|
701 |
elif nargs == 1:
|
|
702 |
value = rargs.pop(0)
|
|
703 |
else:
|
|
704 |
value = tuple(rargs[0:nargs])
|
|
705 |
del rargs[0:nargs]
|
|
706 |
|
|
707 |
else: # option doesn't take a value
|
|
708 |
value = None
|
|
709 |
|
|
710 |
option.process(opt, value, values, self)
|
|
711 |
|
|
712 |
if stop:
|
|
713 |
break
|
|
714 |
|
|
715 |
|
|
716 |
# -- Feedback methods ----------------------------------------------
|
|
717 |
|
|
718 |
def get_prog_name(self):
|
|
719 |
if self.prog is None:
|
|
720 |
return os.path.basename(sys.argv[0])
|
|
721 |
else:
|
|
722 |
return self.prog
|
|
723 |
|
|
724 |
def expand_prog_name(self, s):
|
|
725 |
return string.replace(s, "%prog", self.get_prog_name())
|
|
726 |
|
|
727 |
def get_description(self):
|
|
728 |
return self.expand_prog_name(self.description)
|
|
729 |
|
|
730 |
def exit(self, status=0, msg=None):
|
|
731 |
if msg:
|
|
732 |
sys.stderr.write(msg)
|
|
733 |
sys.exit(status)
|
|
734 |
|
|
735 |
def error(self, msg):
|
|
736 |
"""error(msg : string)
|
|
737 |
|
|
738 |
Print a usage message incorporating 'msg' to stderr and exit.
|
|
739 |
If you override this in a subclass, it should not return -- it
|
|
740 |
should either exit or raise an exception.
|
|
741 |
"""
|
|
742 |
self.print_usage(sys.stderr)
|
|
743 |
self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg))
|
|
744 |
|
|
745 |
def get_usage(self):
|
|
746 |
if self.usage:
|
|
747 |
return self.formatter.format_usage(
|
|
748 |
self.expand_prog_name(self.usage))
|
|
749 |
else:
|
|
750 |
return ""
|
|
751 |
|
|
752 |
def print_usage(self, file=None):
|
|
753 |
"""print_usage(file : file = stdout)
|
|
754 |
|
|
755 |
Print the usage message for the current program (self.usage) to
|
|
756 |
'file' (default stdout). Any occurence of the string "%prog" in
|
|
757 |
self.usage is replaced with the name of the current program
|
|
758 |
(basename of sys.argv[0]). Does nothing if self.usage is empty
|
|
759 |
or not defined.
|
|
760 |
"""
|
|
761 |
if self.usage:
|
|
762 |
if file is None:
|
|
763 |
file = sys.stdout
|
|
764 |
file.write(self.get_usage() + "\n")
|
|
765 |
|
|
766 |
def get_version(self):
|
|
767 |
if self.version:
|
|
768 |
return self.expand_prog_name(self.version)
|
|
769 |
else:
|
|
770 |
return ""
|
|
771 |
|
|
772 |
def print_version(self, file=None):
|
|
773 |
"""print_version(file : file = stdout)
|
|
774 |
|
|
775 |
Print the version message for this program (self.version) to
|
|
776 |
'file' (default stdout). As with print_usage(), any occurence
|
|
777 |
of "%prog" in self.version is replaced by the current program's
|
|
778 |
name. Does nothing if self.version is empty or undefined.
|
|
779 |
"""
|
|
780 |
if self.version:
|
|
781 |
if file is None:
|
|
782 |
file = sys.stdout
|
|
783 |
file.write(self.get_version() + "\n")
|
|
784 |
|
|
785 |
def format_option_help(self, formatter=None):
|
|
786 |
if formatter is None:
|
|
787 |
formatter = self.formatter
|
|
788 |
formatter.store_option_strings(self)
|
|
789 |
result = []
|
|
790 |
result.append(formatter.format_heading(_("options")))
|
|
791 |
formatter.indent()
|
|
792 |
if self.option_list:
|
|
793 |
result.append(OptionContainer.format_option_help(self, formatter))
|
|
794 |
result.append("\n")
|
|
795 |
for group in self.option_groups:
|
|
796 |
result.append(group.format_help(formatter))
|
|
797 |
result.append("\n")
|
|
798 |
formatter.dedent()
|
|
799 |
# Drop the last "\n", or the header if no options or option groups:
|
|
800 |
return string.join(result[:-1], "")
|
|
801 |
|
|
802 |
def format_help(self, formatter=None):
|
|
803 |
if formatter is None:
|
|
804 |
formatter = self.formatter
|
|
805 |
result = []
|
|
806 |
if self.usage:
|
|
807 |
result.append(self.get_usage() + "\n")
|
|
808 |
if self.description:
|
|
809 |
result.append(self.format_description(formatter) + "\n")
|
|
810 |
result.append(self.format_option_help(formatter))
|
|
811 |
return string.join(result, "")
|
|
812 |
|
|
813 |
def print_help(self, file=None):
|
|
814 |
"""print_help(file : file = stdout)
|
|
815 |
|
|
816 |
Print an extended help message, listing all options and any
|
|
817 |
help text provided with them, to 'file' (default stdout).
|
|
818 |
"""
|
|
819 |
if file is None:
|
|
820 |
file = sys.stdout
|
|
821 |
file.write(self.format_help())
|
|
822 |
|
|
823 |
# class OptionParser
|
|
824 |
|
|
825 |
|
|
826 |
def _match_abbrev(s, wordmap):
|
|
827 |
"""_match_abbrev(s : string, wordmap : {string : Option}) -> string
|
|
828 |
|
|
829 |
Return the string key in 'wordmap' for which 's' is an unambiguous
|
|
830 |
abbreviation. If 's' is found to be ambiguous or doesn't match any of
|
|
831 |
'words', raise BadOptionError.
|
|
832 |
"""
|
|
833 |
# Is there an exact match?
|
|
834 |
if wordmap.has_key(s):
|
|
835 |
return s
|
|
836 |
else:
|
|
837 |
# Isolate all words with s as a prefix.
|
|
838 |
possibilities = []
|
|
839 |
for word in wordmap.keys():
|
|
840 |
if string.startswith(word, s):
|
|
841 |
possibilities.append(word)
|
|
842 |
# No exact match, so there had better be just one possibility.
|
|
843 |
if len(possibilities) == 1:
|
|
844 |
return possibilities[0]
|
|
845 |
elif not possibilities:
|
|
846 |
raise errors.BadOptionError(s)
|
|
847 |
else:
|
|
848 |
# More than one possible completion: ambiguous prefix.
|
|
849 |
raise errors.AmbiguousOptionError(s, possibilities)
|