mirror of
https://github.com/python/cpython.git
synced 2025-08-27 12:16:04 +00:00
Upgrade optparse module and tests to Optik 1.5a1:
* add expansion of default values in help text: the string "%default" in an option's help string is expanded to str() of that option's default value, or "none" if no default value. * bug #955889: option default values that happen to be strings are now processed in the same way as values from the command line; this allows generation of nicer help when using custom types. Can be disabled with parser.set_process_default_values(False). * bug #960515: don't crash when generating help for callback options that specify 'type', but not 'dest' or 'metavar'. * feature #815264: change the default help format for short options that take an argument from e.g. "-oARG" to "-o ARG"; add set_short_opt_delimiter() and set_long_opt_delimiter() methods to HelpFormatter to allow (slight) customization of the formatting. * patch #736940: internationalize Optik: all built-in user- targeted literal strings are passed through gettext.gettext(). (If you want translations (.po files), they're not included with Python -- you'll find them in the Optik source distribution from http://optik.sourceforge.net/ .) * bug #878453: respect $COLUMNS environment variable for wrapping help output. * feature #988122: expand "%prog" in the 'description' passed to OptionParser, just like in the 'usage' and 'version' strings. (This is *not* done in the 'description' passed to OptionGroup.)
This commit is contained in:
parent
7357222d0e
commit
eba20e6015
2 changed files with 746 additions and 340 deletions
334
Lib/optparse.py
334
Lib/optparse.py
|
@ -16,13 +16,11 @@ For support, use the optik-users@lists.sourceforge.net mailing list
|
||||||
# Python developers: please do not make changes to this file, since
|
# Python developers: please do not make changes to this file, since
|
||||||
# it is automatically generated from the Optik source code.
|
# it is automatically generated from the Optik source code.
|
||||||
|
|
||||||
__version__ = "1.4.1+"
|
__version__ = "1.5a1"
|
||||||
|
|
||||||
__all__ = ['Option',
|
__all__ = ['Option',
|
||||||
'SUPPRESS_HELP',
|
'SUPPRESS_HELP',
|
||||||
'SUPPRESS_USAGE',
|
'SUPPRESS_USAGE',
|
||||||
'STD_HELP_OPTION',
|
|
||||||
'STD_VERSION_OPTION',
|
|
||||||
'Values',
|
'Values',
|
||||||
'OptionContainer',
|
'OptionContainer',
|
||||||
'OptionGroup',
|
'OptionGroup',
|
||||||
|
@ -37,7 +35,8 @@ __all__ = ['Option',
|
||||||
'BadOptionError']
|
'BadOptionError']
|
||||||
|
|
||||||
__copyright__ = """
|
__copyright__ = """
|
||||||
Copyright (c) 2001-2003 Gregory P. Ward. All rights reserved.
|
Copyright (c) 2001-2004 Gregory P. Ward. All rights reserved.
|
||||||
|
Copyright (c) 2002-2004 Python Software Foundation. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
|
@ -70,6 +69,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
import sys, os
|
import sys, os
|
||||||
import types
|
import types
|
||||||
import textwrap
|
import textwrap
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
def _repr(self):
|
||||||
|
return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self)
|
||||||
|
|
||||||
|
|
||||||
|
# This file was generated from:
|
||||||
|
# Id: option_parser.py,v 1.67 2004/07/24 23:21:21 gward Exp
|
||||||
|
# Id: option.py,v 1.33 2004/07/24 23:21:21 gward Exp
|
||||||
|
# Id: help.py,v 1.15 2004/07/24 23:21:21 gward Exp
|
||||||
|
# Id: errors.py,v 1.9 2004/07/24 23:21:21 gward Exp
|
||||||
|
|
||||||
class OptParseError (Exception):
|
class OptParseError (Exception):
|
||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
|
@ -120,6 +130,8 @@ class HelpFormatter:
|
||||||
formatting help; by default IndentedHelpFormatter is used.
|
formatting help; by default IndentedHelpFormatter is used.
|
||||||
|
|
||||||
Instance attributes:
|
Instance attributes:
|
||||||
|
parser : OptionParser
|
||||||
|
the controlling OptionParser instance
|
||||||
indent_increment : int
|
indent_increment : int
|
||||||
the number of columns to indent per nesting level
|
the number of columns to indent per nesting level
|
||||||
max_help_position : int
|
max_help_position : int
|
||||||
|
@ -128,27 +140,71 @@ class HelpFormatter:
|
||||||
the calculated starting column for option help text;
|
the calculated starting column for option help text;
|
||||||
initially the same as the maximum
|
initially the same as the maximum
|
||||||
width : int
|
width : int
|
||||||
total number of columns for output
|
total number of columns for output (pass None to constructor for
|
||||||
|
this value to be taken from the $COLUMNS environment variable)
|
||||||
level : int
|
level : int
|
||||||
current indentation level
|
current indentation level
|
||||||
current_indent : int
|
current_indent : int
|
||||||
current indentation level (in columns)
|
current indentation level (in columns)
|
||||||
help_width : int
|
help_width : int
|
||||||
number of columns available for option help text (calculated)
|
number of columns available for option help text (calculated)
|
||||||
|
default_tag : str
|
||||||
|
text to replace with each option's default value, "%default"
|
||||||
|
by default. Set to false value to disable default value expansion.
|
||||||
|
option_strings : { Option : str }
|
||||||
|
maps Option instances to the snippet of help text explaining
|
||||||
|
the syntax of that option, e.g. "-h, --help" or
|
||||||
|
"-fFILE, --file=FILE"
|
||||||
|
_short_opt_fmt : str
|
||||||
|
format string controlling how short options with values are
|
||||||
|
printed in help text. Must be either "%s%s" ("-fFILE") or
|
||||||
|
"%s %s" ("-f FILE"), because those are the two syntaxes that
|
||||||
|
Optik supports.
|
||||||
|
_long_opt_fmt : str
|
||||||
|
similar but for long options; must be either "%s %s" ("--file FILE")
|
||||||
|
or "%s=%s" ("--file=FILE").
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
NO_DEFAULT_VALUE = "none"
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
indent_increment,
|
indent_increment,
|
||||||
max_help_position,
|
max_help_position,
|
||||||
width,
|
width,
|
||||||
short_first):
|
short_first):
|
||||||
|
self.parser = None
|
||||||
self.indent_increment = indent_increment
|
self.indent_increment = indent_increment
|
||||||
self.help_position = self.max_help_position = max_help_position
|
self.help_position = self.max_help_position = max_help_position
|
||||||
|
if width is None:
|
||||||
|
try:
|
||||||
|
width = int(os.environ['COLUMNS'])
|
||||||
|
except (KeyError, ValueError):
|
||||||
|
width = 80
|
||||||
|
width -= 2
|
||||||
self.width = width
|
self.width = width
|
||||||
self.current_indent = 0
|
self.current_indent = 0
|
||||||
self.level = 0
|
self.level = 0
|
||||||
self.help_width = width - max_help_position
|
self.help_width = None # computed later
|
||||||
self.short_first = short_first
|
self.short_first = short_first
|
||||||
|
self.default_tag = "%default"
|
||||||
|
self.option_strings = {}
|
||||||
|
self._short_opt_fmt = "%s %s"
|
||||||
|
self._long_opt_fmt = "%s=%s"
|
||||||
|
|
||||||
|
def set_parser(self, parser):
|
||||||
|
self.parser = parser
|
||||||
|
|
||||||
|
def set_short_opt_delimiter(self, delim):
|
||||||
|
if delim not in ("", " "):
|
||||||
|
raise ValueError(
|
||||||
|
"invalid metavar delimiter for short options: %r" % delim)
|
||||||
|
self._short_opt_fmt = "%s" + delim + "%s"
|
||||||
|
|
||||||
|
def set_long_opt_delimiter(self, delim):
|
||||||
|
if delim not in ("=", " "):
|
||||||
|
raise ValueError(
|
||||||
|
"invalid metavar delimiter for long options: %r" % delim)
|
||||||
|
self._long_opt_fmt = "%s" + delim + "%s"
|
||||||
|
|
||||||
def indent(self):
|
def indent(self):
|
||||||
self.current_indent += self.indent_increment
|
self.current_indent += self.indent_increment
|
||||||
|
@ -166,11 +222,24 @@ class HelpFormatter:
|
||||||
raise NotImplementedError, "subclasses must implement"
|
raise NotImplementedError, "subclasses must implement"
|
||||||
|
|
||||||
def format_description(self, description):
|
def format_description(self, description):
|
||||||
|
if not description:
|
||||||
|
return ""
|
||||||
desc_width = self.width - self.current_indent
|
desc_width = self.width - self.current_indent
|
||||||
indent = " "*self.current_indent
|
indent = " "*self.current_indent
|
||||||
return textwrap.fill(description, desc_width,
|
return textwrap.fill(description,
|
||||||
|
desc_width,
|
||||||
initial_indent=indent,
|
initial_indent=indent,
|
||||||
subsequent_indent=indent)
|
subsequent_indent=indent) + "\n"
|
||||||
|
|
||||||
|
def expand_default(self, option):
|
||||||
|
if self.parser is None or not self.default_tag:
|
||||||
|
return option.help
|
||||||
|
|
||||||
|
default_value = self.parser.defaults.get(option.dest)
|
||||||
|
if default_value is NO_DEFAULT or default_value is None:
|
||||||
|
default_value = self.NO_DEFAULT_VALUE
|
||||||
|
|
||||||
|
return option.help.replace(self.default_tag, str(default_value))
|
||||||
|
|
||||||
def format_option(self, option):
|
def format_option(self, option):
|
||||||
# The help for each option consists of two parts:
|
# The help for each option consists of two parts:
|
||||||
|
@ -188,7 +257,7 @@ class HelpFormatter:
|
||||||
# -fFILENAME, --file=FILENAME
|
# -fFILENAME, --file=FILENAME
|
||||||
# read data from FILENAME
|
# read data from FILENAME
|
||||||
result = []
|
result = []
|
||||||
opts = option.option_strings
|
opts = self.option_strings[option]
|
||||||
opt_width = self.help_position - self.current_indent - 2
|
opt_width = self.help_position - self.current_indent - 2
|
||||||
if len(opts) > opt_width:
|
if len(opts) > opt_width:
|
||||||
opts = "%*s%s\n" % (self.current_indent, "", opts)
|
opts = "%*s%s\n" % (self.current_indent, "", opts)
|
||||||
|
@ -198,7 +267,8 @@ class HelpFormatter:
|
||||||
indent_first = 0
|
indent_first = 0
|
||||||
result.append(opts)
|
result.append(opts)
|
||||||
if option.help:
|
if option.help:
|
||||||
help_lines = textwrap.wrap(option.help, self.help_width)
|
help_text = self.expand_default(option)
|
||||||
|
help_lines = textwrap.wrap(help_text, self.help_width)
|
||||||
result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
|
result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
|
||||||
result.extend(["%*s%s\n" % (self.help_position, "", line)
|
result.extend(["%*s%s\n" % (self.help_position, "", line)
|
||||||
for line in help_lines[1:]])
|
for line in help_lines[1:]])
|
||||||
|
@ -211,24 +281,27 @@ class HelpFormatter:
|
||||||
max_len = 0
|
max_len = 0
|
||||||
for opt in parser.option_list:
|
for opt in parser.option_list:
|
||||||
strings = self.format_option_strings(opt)
|
strings = self.format_option_strings(opt)
|
||||||
opt.option_strings = strings
|
self.option_strings[opt] = strings
|
||||||
max_len = max(max_len, len(strings) + self.current_indent)
|
max_len = max(max_len, len(strings) + self.current_indent)
|
||||||
self.indent()
|
self.indent()
|
||||||
for group in parser.option_groups:
|
for group in parser.option_groups:
|
||||||
for opt in group.option_list:
|
for opt in group.option_list:
|
||||||
strings = self.format_option_strings(opt)
|
strings = self.format_option_strings(opt)
|
||||||
opt.option_strings = strings
|
self.option_strings[opt] = strings
|
||||||
max_len = max(max_len, len(strings) + self.current_indent)
|
max_len = max(max_len, len(strings) + self.current_indent)
|
||||||
self.dedent()
|
self.dedent()
|
||||||
self.dedent()
|
self.dedent()
|
||||||
self.help_position = min(max_len + 2, self.max_help_position)
|
self.help_position = min(max_len + 2, self.max_help_position)
|
||||||
|
self.help_width = self.width - self.help_position
|
||||||
|
|
||||||
def format_option_strings(self, option):
|
def format_option_strings(self, option):
|
||||||
"""Return a comma-separated list of option strings & metavariables."""
|
"""Return a comma-separated list of option strings & metavariables."""
|
||||||
if option.takes_value():
|
if option.takes_value():
|
||||||
metavar = option.metavar or option.dest.upper()
|
metavar = option.metavar or option.dest.upper()
|
||||||
short_opts = [sopt + metavar for sopt in option._short_opts]
|
short_opts = [self._short_opt_fmt % (sopt, metavar)
|
||||||
long_opts = [lopt + "=" + metavar for lopt in option._long_opts]
|
for sopt in option._short_opts]
|
||||||
|
long_opts = [self._long_opt_fmt % (lopt, metavar)
|
||||||
|
for lopt in option._long_opts]
|
||||||
else:
|
else:
|
||||||
short_opts = option._short_opts
|
short_opts = option._short_opts
|
||||||
long_opts = option._long_opts
|
long_opts = option._long_opts
|
||||||
|
@ -247,13 +320,13 @@ class IndentedHelpFormatter (HelpFormatter):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
indent_increment=2,
|
indent_increment=2,
|
||||||
max_help_position=24,
|
max_help_position=24,
|
||||||
width=79,
|
width=None,
|
||||||
short_first=1):
|
short_first=1):
|
||||||
HelpFormatter.__init__(
|
HelpFormatter.__init__(
|
||||||
self, indent_increment, max_help_position, width, short_first)
|
self, indent_increment, max_help_position, width, short_first)
|
||||||
|
|
||||||
def format_usage(self, usage):
|
def format_usage(self, usage):
|
||||||
return "usage: %s\n" % usage
|
return _("usage: %s\n") % usage
|
||||||
|
|
||||||
def format_heading(self, heading):
|
def format_heading(self, heading):
|
||||||
return "%*s%s:\n" % (self.current_indent, "", heading)
|
return "%*s%s:\n" % (self.current_indent, "", heading)
|
||||||
|
@ -266,22 +339,22 @@ class TitledHelpFormatter (HelpFormatter):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
indent_increment=0,
|
indent_increment=0,
|
||||||
max_help_position=24,
|
max_help_position=24,
|
||||||
width=79,
|
width=None,
|
||||||
short_first=0):
|
short_first=0):
|
||||||
HelpFormatter.__init__ (
|
HelpFormatter.__init__ (
|
||||||
self, indent_increment, max_help_position, width, short_first)
|
self, indent_increment, max_help_position, width, short_first)
|
||||||
|
|
||||||
def format_usage(self, usage):
|
def format_usage(self, usage):
|
||||||
return "%s %s\n" % (self.format_heading("Usage"), usage)
|
return "%s %s\n" % (self.format_heading(_("Usage")), usage)
|
||||||
|
|
||||||
def format_heading(self, heading):
|
def format_heading(self, heading):
|
||||||
return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))
|
return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))
|
||||||
|
|
||||||
|
|
||||||
_builtin_cvt = { "int" : (int, "integer"),
|
_builtin_cvt = { "int" : (int, _("integer")),
|
||||||
"long" : (long, "long integer"),
|
"long" : (long, _("long integer")),
|
||||||
"float" : (float, "floating-point"),
|
"float" : (float, _("floating-point")),
|
||||||
"complex" : (complex, "complex") }
|
"complex" : (complex, _("complex")) }
|
||||||
|
|
||||||
def check_builtin(option, opt, value):
|
def check_builtin(option, opt, value):
|
||||||
(cvt, what) = _builtin_cvt[option.type]
|
(cvt, what) = _builtin_cvt[option.type]
|
||||||
|
@ -289,8 +362,7 @@ def check_builtin (option, opt, value):
|
||||||
return cvt(value)
|
return cvt(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise OptionValueError(
|
raise OptionValueError(
|
||||||
#"%s: invalid %s argument %r" % (opt, what, value))
|
_("option %s: invalid %s value: %r") % (opt, what, value))
|
||||||
"option %s: invalid %s value: %r" % (opt, what, value))
|
|
||||||
|
|
||||||
def check_choice(option, opt, value):
|
def check_choice(option, opt, value):
|
||||||
if value in option.choices:
|
if value in option.choices:
|
||||||
|
@ -298,12 +370,12 @@ def check_choice(option, opt, value):
|
||||||
else:
|
else:
|
||||||
choices = ", ".join(map(repr, option.choices))
|
choices = ", ".join(map(repr, option.choices))
|
||||||
raise OptionValueError(
|
raise OptionValueError(
|
||||||
"option %s: invalid choice: %r (choose from %s)"
|
_("option %s: invalid choice: %r (choose from %s)")
|
||||||
% (opt, value, choices))
|
% (opt, value, choices))
|
||||||
|
|
||||||
# Not supplying a default is different from a default of None,
|
# Not supplying a default is different from a default of None,
|
||||||
# so we need an explicit "not supplied" value.
|
# so we need an explicit "not supplied" value.
|
||||||
NO_DEFAULT = "NO"+"DEFAULT"
|
NO_DEFAULT = ("NO", "DEFAULT")
|
||||||
|
|
||||||
|
|
||||||
class Option:
|
class Option:
|
||||||
|
@ -495,6 +567,12 @@ class Option:
|
||||||
# No type given? "string" is the most sensible default.
|
# No type given? "string" is the most sensible default.
|
||||||
self.type = "string"
|
self.type = "string"
|
||||||
else:
|
else:
|
||||||
|
# Allow type objects as an alternative to their names.
|
||||||
|
if type(self.type) is type:
|
||||||
|
self.type = self.type.__name__
|
||||||
|
if self.type == "str":
|
||||||
|
self.type = "string"
|
||||||
|
|
||||||
if self.type not in self.TYPES:
|
if self.type not in self.TYPES:
|
||||||
raise OptionError("invalid option type: %r" % self.type, self)
|
raise OptionError("invalid option type: %r" % self.type, self)
|
||||||
if self.action not in self.TYPED_ACTIONS:
|
if self.action not in self.TYPED_ACTIONS:
|
||||||
|
@ -515,8 +593,12 @@ class Option:
|
||||||
"must not supply choices for type %r" % self.type, self)
|
"must not supply choices for type %r" % self.type, self)
|
||||||
|
|
||||||
def _check_dest(self):
|
def _check_dest(self):
|
||||||
if self.action in self.STORE_ACTIONS and self.dest is None:
|
# No destination given, and we need one for this action. The
|
||||||
# No destination given, and we need one for this action.
|
# self.type check is for callbacks that take a value.
|
||||||
|
takes_value = (self.action in self.STORE_ACTIONS or
|
||||||
|
self.type is not None)
|
||||||
|
if self.dest is None and takes_value:
|
||||||
|
|
||||||
# Glean a destination from the first long option string,
|
# Glean a destination from the first long option string,
|
||||||
# or from the first short option string if no long options.
|
# or from the first short option string if no long options.
|
||||||
if self._long_opts:
|
if self._long_opts:
|
||||||
|
@ -582,9 +664,17 @@ class Option:
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "/".join(self._short_opts + self._long_opts)
|
return "/".join(self._short_opts + self._long_opts)
|
||||||
|
|
||||||
|
__repr__ = _repr
|
||||||
|
|
||||||
def takes_value(self):
|
def takes_value(self):
|
||||||
return self.type is not None
|
return self.type is not None
|
||||||
|
|
||||||
|
def get_opt_string(self):
|
||||||
|
if self._long_opts:
|
||||||
|
return self._long_opts[0]
|
||||||
|
else:
|
||||||
|
return self._short_opts[0]
|
||||||
|
|
||||||
|
|
||||||
# -- Processing methods --------------------------------------------
|
# -- Processing methods --------------------------------------------
|
||||||
|
|
||||||
|
@ -595,15 +685,18 @@ class Option:
|
||||||
else:
|
else:
|
||||||
return checker(self, opt, value)
|
return checker(self, opt, value)
|
||||||
|
|
||||||
|
def convert_value(self, opt, value):
|
||||||
|
if value is not None:
|
||||||
|
if self.nargs == 1:
|
||||||
|
return self.check_value(opt, value)
|
||||||
|
else:
|
||||||
|
return tuple([self.check_value(opt, v) for v in value])
|
||||||
|
|
||||||
def process(self, opt, value, values, parser):
|
def process(self, opt, value, values, parser):
|
||||||
|
|
||||||
# First, convert the value(s) to the right type. Howl if any
|
# First, convert the value(s) to the right type. Howl if any
|
||||||
# value(s) are bogus.
|
# value(s) are bogus.
|
||||||
if value is not None:
|
value = self.convert_value(opt, value)
|
||||||
if self.nargs == 1:
|
|
||||||
value = self.check_value(opt, value)
|
|
||||||
else:
|
|
||||||
value = tuple([self.check_value(opt, v) for v in value])
|
|
||||||
|
|
||||||
# And then take whatever action is expected of us.
|
# And then take whatever action is expected of us.
|
||||||
# This is a separate method to make life easier for
|
# This is a separate method to make life easier for
|
||||||
|
@ -642,19 +735,18 @@ class Option:
|
||||||
# class Option
|
# class Option
|
||||||
|
|
||||||
|
|
||||||
def get_prog_name ():
|
|
||||||
return os.path.basename(sys.argv[0])
|
|
||||||
|
|
||||||
|
|
||||||
SUPPRESS_HELP = "SUPPRESS"+"HELP"
|
SUPPRESS_HELP = "SUPPRESS"+"HELP"
|
||||||
SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
|
SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
|
||||||
|
|
||||||
STD_HELP_OPTION = Option("-h", "--help",
|
# For compatibility with Python 2.2
|
||||||
action="help",
|
try:
|
||||||
help="show this help message and exit")
|
True, False
|
||||||
STD_VERSION_OPTION = Option("--version",
|
except NameError:
|
||||||
action="version",
|
(True, False) = (1, 0)
|
||||||
help="show program's version number and exit")
|
try:
|
||||||
|
basestring
|
||||||
|
except NameError:
|
||||||
|
basestring = (str, unicode)
|
||||||
|
|
||||||
|
|
||||||
class Values:
|
class Values:
|
||||||
|
@ -664,9 +756,21 @@ class Values:
|
||||||
for (attr, val) in defaults.items():
|
for (attr, val) in defaults.items():
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
|
|
||||||
def __repr__ (self):
|
def __str__(self):
|
||||||
return ("<%s at 0x%x: %r>"
|
return str(self.__dict__)
|
||||||
% (self.__class__.__name__, id(self), self.__dict__))
|
|
||||||
|
__repr__ = _repr
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if isinstance(other, Values):
|
||||||
|
return self.__dict__ == other.__dict__
|
||||||
|
elif isinstance(other, dict):
|
||||||
|
return self.__dict__ == other
|
||||||
|
else:
|
||||||
|
return false
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not (self == other)
|
||||||
|
|
||||||
def _update_careful(self, dict):
|
def _update_careful(self, dict):
|
||||||
"""
|
"""
|
||||||
|
@ -780,6 +884,9 @@ class OptionContainer:
|
||||||
def set_description(self, description):
|
def set_description(self, description):
|
||||||
self.description = description
|
self.description = description
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return self.description
|
||||||
|
|
||||||
|
|
||||||
# -- Option-adding methods -----------------------------------------
|
# -- Option-adding methods -----------------------------------------
|
||||||
|
|
||||||
|
@ -882,17 +989,15 @@ class OptionContainer:
|
||||||
return "".join(result)
|
return "".join(result)
|
||||||
|
|
||||||
def format_description(self, formatter):
|
def format_description(self, formatter):
|
||||||
if self.description:
|
return formatter.format_description(self.get_description())
|
||||||
return formatter.format_description(self.description)
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def format_help(self, formatter):
|
def format_help(self, formatter):
|
||||||
|
result = []
|
||||||
if self.description:
|
if self.description:
|
||||||
desc = self.format_description(formatter) + "\n"
|
result.append(self.format_description(formatter))
|
||||||
else:
|
if self.option_list:
|
||||||
desc = ""
|
result.append(self.format_option_help(formatter))
|
||||||
return desc + self.format_option_help(formatter)
|
return "\n".join(result)
|
||||||
|
|
||||||
|
|
||||||
class OptionGroup (OptionContainer):
|
class OptionGroup (OptionContainer):
|
||||||
|
@ -937,7 +1042,12 @@ class OptionParser (OptionContainer):
|
||||||
the name of the current program (to override
|
the name of the current program (to override
|
||||||
os.path.basename(sys.argv[0])).
|
os.path.basename(sys.argv[0])).
|
||||||
|
|
||||||
allow_interspersed_args : boolean = true
|
option_groups : [OptionGroup]
|
||||||
|
list of option groups in this parser (option groups are
|
||||||
|
irrelevant for parsing the command-line, but very useful
|
||||||
|
for generating help)
|
||||||
|
|
||||||
|
allow_interspersed_args : bool = true
|
||||||
if true, positional arguments may be interspersed with options.
|
if true, positional arguments may be interspersed with options.
|
||||||
Assuming -a and -b each take a single argument, the command-line
|
Assuming -a and -b each take a single argument, the command-line
|
||||||
-ablah foo bar -bboo baz
|
-ablah foo bar -bboo baz
|
||||||
|
@ -950,6 +1060,14 @@ class OptionParser (OptionContainer):
|
||||||
Python's getopt module, Perl's Getopt::Std, and other argument-
|
Python's getopt module, Perl's Getopt::Std, and other argument-
|
||||||
parsing libraries, but it is generally annoying to users.)
|
parsing libraries, but it is generally annoying to users.)
|
||||||
|
|
||||||
|
process_default_values : bool = true
|
||||||
|
if true, option default values are processed similarly to option
|
||||||
|
values from the command line: that is, they are passed to the
|
||||||
|
type-checking function for the option's type (as long as the
|
||||||
|
default value is a string). (This really only matters if you
|
||||||
|
have defined custom types; see SF bug #955889.) Set it to false
|
||||||
|
to restore the behaviour of Optik 1.4.1 and earlier.
|
||||||
|
|
||||||
rargs : [string]
|
rargs : [string]
|
||||||
the argument list currently being parsed. Only set when
|
the argument list currently being parsed. Only set when
|
||||||
parse_args() is active, and continually trimmed down as
|
parse_args() is active, and continually trimmed down as
|
||||||
|
@ -980,22 +1098,24 @@ class OptionParser (OptionContainer):
|
||||||
conflict_handler="error",
|
conflict_handler="error",
|
||||||
description=None,
|
description=None,
|
||||||
formatter=None,
|
formatter=None,
|
||||||
add_help_option=1,
|
add_help_option=True,
|
||||||
prog=None):
|
prog=None):
|
||||||
OptionContainer.__init__(
|
OptionContainer.__init__(
|
||||||
self, option_class, conflict_handler, description)
|
self, option_class, conflict_handler, description)
|
||||||
self.set_usage(usage)
|
self.set_usage(usage)
|
||||||
self.prog = prog
|
self.prog = prog
|
||||||
self.version = version
|
self.version = version
|
||||||
self.allow_interspersed_args = 1
|
self.allow_interspersed_args = True
|
||||||
|
self.process_default_values = True
|
||||||
if formatter is None:
|
if formatter is None:
|
||||||
formatter = IndentedHelpFormatter()
|
formatter = IndentedHelpFormatter()
|
||||||
self.formatter = formatter
|
self.formatter = formatter
|
||||||
|
self.formatter.set_parser(self)
|
||||||
|
|
||||||
# Populate the option list; initial sources are the
|
# Populate the option list; initial sources are the
|
||||||
# standard_option_list class attribute, the 'option_list'
|
# standard_option_list class attribute, the 'option_list'
|
||||||
# argument, and the STD_VERSION_OPTION (if 'version' supplied)
|
# argument, and (if applicable) the _add_version_option() and
|
||||||
# and STD_HELP_OPTION globals.
|
# _add_help_option() methods.
|
||||||
self._populate_option_list(option_list,
|
self._populate_option_list(option_list,
|
||||||
add_help=add_help_option)
|
add_help=add_help_option)
|
||||||
|
|
||||||
|
@ -1009,15 +1129,25 @@ class OptionParser (OptionContainer):
|
||||||
self.option_groups = []
|
self.option_groups = []
|
||||||
self._create_option_mappings()
|
self._create_option_mappings()
|
||||||
|
|
||||||
def _populate_option_list (self, option_list, add_help=1):
|
def _add_help_option(self):
|
||||||
|
self.add_option("-h", "--help",
|
||||||
|
action="help",
|
||||||
|
help=_("show this help message and exit"))
|
||||||
|
|
||||||
|
def _add_version_option(self):
|
||||||
|
self.add_option("--version",
|
||||||
|
action="version",
|
||||||
|
help=_("show program's version number and exit"))
|
||||||
|
|
||||||
|
def _populate_option_list(self, option_list, add_help=True):
|
||||||
if self.standard_option_list:
|
if self.standard_option_list:
|
||||||
self.add_options(self.standard_option_list)
|
self.add_options(self.standard_option_list)
|
||||||
if option_list:
|
if option_list:
|
||||||
self.add_options(option_list)
|
self.add_options(option_list)
|
||||||
if self.version:
|
if self.version:
|
||||||
self.add_option(STD_VERSION_OPTION)
|
self._add_version_option()
|
||||||
if add_help:
|
if add_help:
|
||||||
self.add_option(STD_HELP_OPTION)
|
self._add_help_option()
|
||||||
|
|
||||||
def _init_parsing_state(self):
|
def _init_parsing_state(self):
|
||||||
# These are set in parse_args() for the convenience of callbacks.
|
# These are set in parse_args() for the convenience of callbacks.
|
||||||
|
@ -1025,30 +1155,28 @@ class OptionParser (OptionContainer):
|
||||||
self.largs = None
|
self.largs = None
|
||||||
self.values = None
|
self.values = None
|
||||||
|
|
||||||
def _get_prog_name(self):
|
|
||||||
if self.prog:
|
|
||||||
return self.prog
|
|
||||||
else:
|
|
||||||
return get_prog_name()
|
|
||||||
|
|
||||||
# -- Simple modifier methods ---------------------------------------
|
# -- Simple modifier methods ---------------------------------------
|
||||||
|
|
||||||
def set_usage(self, usage):
|
def set_usage(self, usage):
|
||||||
if usage is None:
|
if usage is None:
|
||||||
self.usage = "%prog [options]"
|
self.usage = _("%prog [options]")
|
||||||
elif usage is SUPPRESS_USAGE:
|
elif usage is SUPPRESS_USAGE:
|
||||||
self.usage = None
|
self.usage = None
|
||||||
elif usage.lower().startswith("usage: "):
|
# For backwards compatibility with Optik 1.3 and earlier.
|
||||||
# for backwards compatibility with Optik 1.3 and earlier
|
elif usage.startswith("usage:" + " "):
|
||||||
self.usage = usage[7:]
|
self.usage = usage[7:]
|
||||||
else:
|
else:
|
||||||
self.usage = usage
|
self.usage = usage
|
||||||
|
|
||||||
def enable_interspersed_args(self):
|
def enable_interspersed_args(self):
|
||||||
self.allow_interspersed_args = 1
|
self.allow_interspersed_args = True
|
||||||
|
|
||||||
def disable_interspersed_args(self):
|
def disable_interspersed_args(self):
|
||||||
self.allow_interspersed_args = 0
|
self.allow_interspersed_args = False
|
||||||
|
|
||||||
|
def set_process_default_values(self, process):
|
||||||
|
self.process_default_values = process
|
||||||
|
|
||||||
def set_default(self, dest, value):
|
def set_default(self, dest, value):
|
||||||
self.defaults[dest] = value
|
self.defaults[dest] = value
|
||||||
|
@ -1056,9 +1184,26 @@ class OptionParser (OptionContainer):
|
||||||
def set_defaults(self, **kwargs):
|
def set_defaults(self, **kwargs):
|
||||||
self.defaults.update(kwargs)
|
self.defaults.update(kwargs)
|
||||||
|
|
||||||
|
def _get_all_options(self):
|
||||||
|
options = self.option_list[:]
|
||||||
|
for group in self.option_groups:
|
||||||
|
options.extend(group.option_list)
|
||||||
|
return options
|
||||||
|
|
||||||
def get_default_values(self):
|
def get_default_values(self):
|
||||||
|
if not self.process_default_values:
|
||||||
|
# Old, pre-Optik 1.5 behaviour.
|
||||||
return Values(self.defaults)
|
return Values(self.defaults)
|
||||||
|
|
||||||
|
defaults = self.defaults.copy()
|
||||||
|
for option in self._get_all_options():
|
||||||
|
default = defaults.get(option.dest)
|
||||||
|
if isinstance(default, basestring):
|
||||||
|
opt_str = option.get_opt_string()
|
||||||
|
defaults[option.dest] = option.check_value(opt_str, default)
|
||||||
|
|
||||||
|
return Values(defaults)
|
||||||
|
|
||||||
|
|
||||||
# -- OptionGroup methods -------------------------------------------
|
# -- OptionGroup methods -------------------------------------------
|
||||||
|
|
||||||
|
@ -1214,10 +1359,10 @@ class OptionParser (OptionContainer):
|
||||||
if "=" in arg:
|
if "=" in arg:
|
||||||
(opt, next_arg) = arg.split("=", 1)
|
(opt, next_arg) = arg.split("=", 1)
|
||||||
rargs.insert(0, next_arg)
|
rargs.insert(0, next_arg)
|
||||||
had_explicit_value = 1
|
had_explicit_value = True
|
||||||
else:
|
else:
|
||||||
opt = arg
|
opt = arg
|
||||||
had_explicit_value = 0
|
had_explicit_value = False
|
||||||
|
|
||||||
opt = self._match_long_opt(opt)
|
opt = self._match_long_opt(opt)
|
||||||
option = self._long_opt[opt]
|
option = self._long_opt[opt]
|
||||||
|
@ -1225,9 +1370,9 @@ class OptionParser (OptionContainer):
|
||||||
nargs = option.nargs
|
nargs = option.nargs
|
||||||
if len(rargs) < nargs:
|
if len(rargs) < nargs:
|
||||||
if nargs == 1:
|
if nargs == 1:
|
||||||
self.error("%s option requires a value" % opt)
|
self.error(_("%s option requires an argument") % opt)
|
||||||
else:
|
else:
|
||||||
self.error("%s option requires %d values"
|
self.error(_("%s option requires %d arguments")
|
||||||
% (opt, nargs))
|
% (opt, nargs))
|
||||||
elif nargs == 1:
|
elif nargs == 1:
|
||||||
value = rargs.pop(0)
|
value = rargs.pop(0)
|
||||||
|
@ -1236,7 +1381,7 @@ class OptionParser (OptionContainer):
|
||||||
del rargs[0:nargs]
|
del rargs[0:nargs]
|
||||||
|
|
||||||
elif had_explicit_value:
|
elif had_explicit_value:
|
||||||
self.error("%s option does not take a value" % opt)
|
self.error(_("%s option does not take a value") % opt)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
value = None
|
value = None
|
||||||
|
@ -1245,7 +1390,7 @@ class OptionParser (OptionContainer):
|
||||||
|
|
||||||
def _process_short_opts(self, rargs, values):
|
def _process_short_opts(self, rargs, values):
|
||||||
arg = rargs.pop(0)
|
arg = rargs.pop(0)
|
||||||
stop = 0
|
stop = False
|
||||||
i = 1
|
i = 1
|
||||||
for ch in arg[1:]:
|
for ch in arg[1:]:
|
||||||
opt = "-" + ch
|
opt = "-" + ch
|
||||||
|
@ -1253,20 +1398,20 @@ class OptionParser (OptionContainer):
|
||||||
i += 1 # we have consumed a character
|
i += 1 # we have consumed a character
|
||||||
|
|
||||||
if not option:
|
if not option:
|
||||||
self.error("no such option: %s" % opt)
|
self.error(_("no such option: %s") % opt)
|
||||||
if option.takes_value():
|
if option.takes_value():
|
||||||
# Any characters left in arg? Pretend they're the
|
# Any characters left in arg? Pretend they're the
|
||||||
# next arg, and stop consuming characters of arg.
|
# next arg, and stop consuming characters of arg.
|
||||||
if i < len(arg):
|
if i < len(arg):
|
||||||
rargs.insert(0, arg[i:])
|
rargs.insert(0, arg[i:])
|
||||||
stop = 1
|
stop = True
|
||||||
|
|
||||||
nargs = option.nargs
|
nargs = option.nargs
|
||||||
if len(rargs) < nargs:
|
if len(rargs) < nargs:
|
||||||
if nargs == 1:
|
if nargs == 1:
|
||||||
self.error("%s option requires a value" % opt)
|
self.error(_("%s option requires an argument") % opt)
|
||||||
else:
|
else:
|
||||||
self.error("%s option requires %s values"
|
self.error(_("%s option requires %d arguments")
|
||||||
% (opt, nargs))
|
% (opt, nargs))
|
||||||
elif nargs == 1:
|
elif nargs == 1:
|
||||||
value = rargs.pop(0)
|
value = rargs.pop(0)
|
||||||
|
@ -1285,6 +1430,18 @@ class OptionParser (OptionContainer):
|
||||||
|
|
||||||
# -- Feedback methods ----------------------------------------------
|
# -- Feedback methods ----------------------------------------------
|
||||||
|
|
||||||
|
def get_prog_name(self):
|
||||||
|
if self.prog is None:
|
||||||
|
return os.path.basename(sys.argv[0])
|
||||||
|
else:
|
||||||
|
return self.prog
|
||||||
|
|
||||||
|
def expand_prog_name(self, s):
|
||||||
|
return s.replace("%prog", self.get_prog_name())
|
||||||
|
|
||||||
|
def get_description(self):
|
||||||
|
return self.expand_prog_name(self.description)
|
||||||
|
|
||||||
def error(self, msg):
|
def error(self, msg):
|
||||||
"""error(msg : string)
|
"""error(msg : string)
|
||||||
|
|
||||||
|
@ -1293,12 +1450,13 @@ class OptionParser (OptionContainer):
|
||||||
should either exit or raise an exception.
|
should either exit or raise an exception.
|
||||||
"""
|
"""
|
||||||
self.print_usage(sys.stderr)
|
self.print_usage(sys.stderr)
|
||||||
sys.exit("%s: error: %s" % (self._get_prog_name(), msg))
|
sys.stderr.write("%s: error: %s\n" % (self.get_prog_name(), msg))
|
||||||
|
sys.exit(2) # command-line usage error
|
||||||
|
|
||||||
def get_usage(self):
|
def get_usage(self):
|
||||||
if self.usage:
|
if self.usage:
|
||||||
return self.formatter.format_usage(
|
return self.formatter.format_usage(
|
||||||
self.usage.replace("%prog", self._get_prog_name()))
|
self.expand_prog_name(self.usage))
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -1316,7 +1474,7 @@ class OptionParser (OptionContainer):
|
||||||
|
|
||||||
def get_version(self):
|
def get_version(self):
|
||||||
if self.version:
|
if self.version:
|
||||||
return self.version.replace("%prog", self._get_prog_name())
|
return self.expand_prog_name(self.version)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -1336,7 +1494,7 @@ class OptionParser (OptionContainer):
|
||||||
formatter = self.formatter
|
formatter = self.formatter
|
||||||
formatter.store_option_strings(self)
|
formatter.store_option_strings(self)
|
||||||
result = []
|
result = []
|
||||||
result.append(formatter.format_heading("options"))
|
result.append(formatter.format_heading(_("options")))
|
||||||
formatter.indent()
|
formatter.indent()
|
||||||
if self.option_list:
|
if self.option_list:
|
||||||
result.append(OptionContainer.format_option_help(self, formatter))
|
result.append(OptionContainer.format_option_help(self, formatter))
|
||||||
|
@ -1390,10 +1548,10 @@ def _match_abbrev (s, wordmap):
|
||||||
if len(possibilities) == 1:
|
if len(possibilities) == 1:
|
||||||
return possibilities[0]
|
return possibilities[0]
|
||||||
elif not possibilities:
|
elif not possibilities:
|
||||||
raise BadOptionError("no such option: %s" % s)
|
raise BadOptionError(_("no such option: %s") % s)
|
||||||
else:
|
else:
|
||||||
# More than one possible completion: ambiguous prefix.
|
# More than one possible completion: ambiguous prefix.
|
||||||
raise BadOptionError("ambiguous option: %s (%s?)"
|
raise BadOptionError(_("ambiguous option: %s (%s?)")
|
||||||
% (s, ", ".join(possibilities)))
|
% (s, ", ".join(possibilities)))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,7 @@ from test import test_support
|
||||||
from optparse import make_option, Option, IndentedHelpFormatter, \
|
from optparse import make_option, Option, IndentedHelpFormatter, \
|
||||||
TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
|
TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
|
||||||
SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
|
SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
|
||||||
BadOptionError, OptionValueError
|
BadOptionError, OptionValueError, _match_abbrev
|
||||||
from optparse import _match_abbrev
|
|
||||||
|
|
||||||
# Do the right thing with boolean values for all known Python versions.
|
|
||||||
try:
|
|
||||||
True, False
|
|
||||||
except NameError:
|
|
||||||
(True, False) = (1, 0)
|
|
||||||
|
|
||||||
class BaseTest(unittest.TestCase):
|
class BaseTest(unittest.TestCase):
|
||||||
def assertParseOK(self, args, expected_opts, expected_positional_args):
|
def assertParseOK(self, args, expected_opts, expected_positional_args):
|
||||||
|
@ -60,50 +53,62 @@ Args were %(args)s.""" % locals ())
|
||||||
|
|
||||||
return (options, positional_args)
|
return (options, positional_args)
|
||||||
|
|
||||||
def assertRaises(self, func, expected_exception, expected_output,
|
def assertRaises(self,
|
||||||
|
func,
|
||||||
|
args,
|
||||||
|
kwargs,
|
||||||
|
expected_exception,
|
||||||
|
expected_output,
|
||||||
get_output=None,
|
get_output=None,
|
||||||
funcargs=[], funckwargs={}):
|
exact_match=False):
|
||||||
"""Assert the expected exception is raised when calling a function.
|
"""Assert the expected exception is raised when calling a function.
|
||||||
|
|
||||||
Also check whether the right error message is given for a given error.
|
Also check whether the right error message is given for a given error.
|
||||||
|
|
||||||
Keyword arguments:
|
Arguments:
|
||||||
func -- The function to be called.
|
func -- the function to call
|
||||||
expected_exception -- The exception that should be raised.
|
args -- positional arguments to `func`
|
||||||
expected_output -- The output we expect to see.
|
kwargs -- keyword arguments to `func`
|
||||||
get_output -- The function to call to get the output.
|
expected_exception -- exception that should be raised
|
||||||
funcargs -- The arguments `func` should be called with.
|
expected_output -- output we expect to see
|
||||||
funckwargs -- The keyword arguments `func` should be called with.
|
get_output -- function to call to get the output
|
||||||
|
exact_match -- whether output must exactly match expected output,
|
||||||
|
or merely contain it
|
||||||
|
|
||||||
Returns the exception raised for further testing.
|
Returns the exception raised for further testing.
|
||||||
"""
|
"""
|
||||||
|
if args is None:
|
||||||
|
args = ()
|
||||||
|
if kwargs is None:
|
||||||
|
kwargs = {}
|
||||||
if get_output is None:
|
if get_output is None:
|
||||||
get_output = self.exception
|
get_output = self.exception
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out = func(*funcargs, **funckwargs)
|
out = func(*args, **kwargs)
|
||||||
except expected_exception, err:
|
except expected_exception, err:
|
||||||
output = get_output(err)
|
actual_output = get_output(err)
|
||||||
|
|
||||||
self.failUnless(output.find(expected_output) != -1,
|
if exact_match:
|
||||||
"""
|
match = actual_output == expected_exception
|
||||||
Message was:
|
else:
|
||||||
%(output)s
|
match = actual_output.find(expected_output) != -1
|
||||||
Should contain:
|
|
||||||
%(expected_output)s
|
self.assert_(match,
|
||||||
Function called:
|
"""mismatched output
|
||||||
%(func)s
|
expected output:
|
||||||
With args/kwargs:
|
'''%(expected_output)s'''
|
||||||
%(funcargs)s/%(funckwargs)s""" % locals())
|
actual output:
|
||||||
|
'''%(actual_output)s'''
|
||||||
|
""" % locals())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
else:
|
else:
|
||||||
self.fail("""
|
self.fail("""expected exception %(expected_exception)s not raised
|
||||||
No %(expected_exception)s raised.
|
called %(func)r
|
||||||
Function called:
|
with args %(args)r
|
||||||
%(func)s
|
and kwargs %(kwargs)r
|
||||||
With args/kwargs:
|
""" % locals ())
|
||||||
%(funcargs)s/%(funckwargs)s""" % locals ())
|
|
||||||
|
|
||||||
# -- Functions to be used as the get_output argument to assertRaises ------
|
# -- Functions to be used as the get_output argument to assertRaises ------
|
||||||
|
|
||||||
|
@ -113,23 +118,38 @@ With args/kwargs:
|
||||||
def redirected_stdout(self, err):
|
def redirected_stdout(self, err):
|
||||||
return sys.stdout.getvalue()
|
return sys.stdout.getvalue()
|
||||||
|
|
||||||
|
def redirected_stderr(self, err):
|
||||||
|
return sys.stderr.getvalue()
|
||||||
|
|
||||||
# -- Assertions used in more than one class --------------------
|
# -- Assertions used in more than one class --------------------
|
||||||
|
|
||||||
def assertParseFail(self, cmdline_args, expected_output):
|
def assertParseFail(self, cmdline_args, expected_output):
|
||||||
"""Assert the parser fails with the expected message."""
|
"""Assert the parser fails with the expected message."""
|
||||||
self.assertRaises(self.parser.parse_args, SystemExit, expected_output,
|
sys.stderr = StringIO()
|
||||||
funcargs=[cmdline_args])
|
self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
|
||||||
|
SystemExit, expected_output,
|
||||||
|
self.redirected_stderr)
|
||||||
|
sys.stderr = sys.__stderr__
|
||||||
|
|
||||||
def assertStdoutEquals(self, cmdline_args, expected_output):
|
def assertStdoutEquals(self, cmdline_args, expected_output):
|
||||||
"""Assert the parser prints the expected output on stdout."""
|
"""Assert the parser prints the expected output on stdout."""
|
||||||
sys.stdout = StringIO()
|
sys.stdout = StringIO()
|
||||||
self.assertRaises(self.parser.parse_args, SystemExit, expected_output,
|
self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
|
||||||
self.redirected_stdout, [cmdline_args])
|
SystemExit, expected_output,
|
||||||
|
self.redirected_stdout)
|
||||||
sys.stdout = sys.__stdout__
|
sys.stdout = sys.__stdout__
|
||||||
|
|
||||||
def assertTypeError(self, func, expected_output, *args):
|
def assertTypeError(self, func, expected_output, *args):
|
||||||
"""Assert a TypeError is raised when executing func."""
|
"""Assert a TypeError is raised when executing func."""
|
||||||
self.assertRaises(func, TypeError, expected_output, funcargs=args)
|
self.assertRaises(func, args, None, TypeError, expected_output)
|
||||||
|
|
||||||
|
def assertHelp(self, parser, expected_help):
|
||||||
|
actual_help = parser.format_help()
|
||||||
|
if actual_help != expected_help:
|
||||||
|
raise self.failureException(
|
||||||
|
'help text failure; expected:\n"' +
|
||||||
|
expected_help + '"; got:\n"' +
|
||||||
|
actual_help + '"\n')
|
||||||
|
|
||||||
# -- Test make_option() aka Option -------------------------------------
|
# -- Test make_option() aka Option -------------------------------------
|
||||||
|
|
||||||
|
@ -142,8 +162,8 @@ class TestOptionChecks(BaseTest):
|
||||||
self.parser = OptionParser(usage=SUPPRESS_USAGE)
|
self.parser = OptionParser(usage=SUPPRESS_USAGE)
|
||||||
|
|
||||||
def assertOptionError(self, expected_output, args=[], kwargs={}):
|
def assertOptionError(self, expected_output, args=[], kwargs={}):
|
||||||
self.assertRaises(make_option, OptionError, expected_output,
|
self.assertRaises(make_option, args, kwargs,
|
||||||
funcargs=args, funckwargs=kwargs)
|
OptionError, expected_output)
|
||||||
|
|
||||||
def test_opt_string_empty(self):
|
def test_opt_string_empty(self):
|
||||||
self.assertTypeError(make_option,
|
self.assertTypeError(make_option,
|
||||||
|
@ -175,6 +195,8 @@ class TestOptionChecks(BaseTest):
|
||||||
def test_type_invalid(self):
|
def test_type_invalid(self):
|
||||||
self.assertOptionError("invalid option type: 'foo'",
|
self.assertOptionError("invalid option type: 'foo'",
|
||||||
["-b"], {'type': 'foo'})
|
["-b"], {'type': 'foo'})
|
||||||
|
self.assertOptionError("invalid option type: 'tuple'",
|
||||||
|
["-b"], {'type': tuple})
|
||||||
|
|
||||||
def test_no_type_for_action(self):
|
def test_no_type_for_action(self):
|
||||||
self.assertOptionError("must not supply a type for action 'count'",
|
self.assertOptionError("must not supply a type for action 'count'",
|
||||||
|
@ -304,8 +326,204 @@ class TestOptionParser(BaseTest):
|
||||||
self.assert_removed()
|
self.assert_removed()
|
||||||
|
|
||||||
def test_remove_nonexistent(self):
|
def test_remove_nonexistent(self):
|
||||||
self.assertRaises(self.parser.remove_option, ValueError,
|
self.assertRaises(self.parser.remove_option, ('foo',), None,
|
||||||
"no such option 'foo'", funcargs=['foo'])
|
ValueError, "no such option 'foo'")
|
||||||
|
|
||||||
|
class TestTypeAliases(BaseTest):
|
||||||
|
def setUp(self):
|
||||||
|
self.parser = OptionParser()
|
||||||
|
|
||||||
|
def test_type_aliases(self):
|
||||||
|
self.parser.add_option("-x", type=int)
|
||||||
|
self.parser.add_option("-s", type=str)
|
||||||
|
self.parser.add_option("-t", type="str")
|
||||||
|
self.assertEquals(self.parser.get_option("-x").type, "int")
|
||||||
|
self.assertEquals(self.parser.get_option("-s").type, "string")
|
||||||
|
self.assertEquals(self.parser.get_option("-t").type, "string")
|
||||||
|
|
||||||
|
|
||||||
|
# Custom type for testing processing of default values.
|
||||||
|
_time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
|
||||||
|
|
||||||
|
def _check_duration(option, opt, value):
|
||||||
|
try:
|
||||||
|
if value[-1].isdigit():
|
||||||
|
return int(value)
|
||||||
|
else:
|
||||||
|
return int(value[:-1]) * _time_units[value[-1]]
|
||||||
|
except ValueError, IndexError:
|
||||||
|
raise OptionValueError(
|
||||||
|
'option %s: invalid duration: %r' % (opt, value))
|
||||||
|
|
||||||
|
class DurationOption(Option):
|
||||||
|
TYPES = Option.TYPES + ('duration',)
|
||||||
|
TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
|
||||||
|
TYPE_CHECKER['duration'] = _check_duration
|
||||||
|
|
||||||
|
class TestDefaultValues(BaseTest):
|
||||||
|
def setUp(self):
|
||||||
|
self.parser = OptionParser()
|
||||||
|
self.parser.add_option("-v", "--verbose", default=True)
|
||||||
|
self.parser.add_option("-q", "--quiet", dest='verbose')
|
||||||
|
self.parser.add_option("-n", type="int", default=37)
|
||||||
|
self.parser.add_option("-m", type="int")
|
||||||
|
self.parser.add_option("-s", default="foo")
|
||||||
|
self.parser.add_option("-t")
|
||||||
|
self.parser.add_option("-u", default=None)
|
||||||
|
self.expected = { 'verbose': True,
|
||||||
|
'n': 37,
|
||||||
|
'm': None,
|
||||||
|
's': "foo",
|
||||||
|
't': None,
|
||||||
|
'u': None }
|
||||||
|
|
||||||
|
def test_basic_defaults(self):
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
def test_mixed_defaults_post(self):
|
||||||
|
self.parser.set_defaults(n=42, m=-100)
|
||||||
|
self.expected.update({'n': 42, 'm': -100})
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
def test_mixed_defaults_pre(self):
|
||||||
|
self.parser.set_defaults(x="barf", y="blah")
|
||||||
|
self.parser.add_option("-x", default="frob")
|
||||||
|
self.parser.add_option("-y")
|
||||||
|
|
||||||
|
self.expected.update({'x': "frob", 'y': "blah"})
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
self.parser.remove_option("-y")
|
||||||
|
self.parser.add_option("-y", default=None)
|
||||||
|
self.expected.update({'y': None})
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
def test_process_default(self):
|
||||||
|
self.parser.option_class = DurationOption
|
||||||
|
self.parser.add_option("-d", type="duration", default=300)
|
||||||
|
self.parser.add_option("-e", type="duration", default="6m")
|
||||||
|
self.parser.set_defaults(n="42")
|
||||||
|
self.expected.update({'d': 300, 'e': 360, 'n': 42})
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
self.parser.set_process_default_values(False)
|
||||||
|
self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
|
||||||
|
self.assertEqual(self.parser.get_default_values(), self.expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestProgName(BaseTest):
|
||||||
|
"""
|
||||||
|
Test that %prog expands to the right thing in usage, version,
|
||||||
|
and help strings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def assertUsage(self, parser, expected_usage):
|
||||||
|
self.assertEqual(parser.get_usage(), expected_usage)
|
||||||
|
|
||||||
|
def assertVersion(self, parser, expected_version):
|
||||||
|
self.assertEqual(parser.get_version(), expected_version)
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_progname(self):
|
||||||
|
# Make sure that program name taken from sys.argv[0] by default.
|
||||||
|
sys.argv[0] = "/foo/bar/baz.py"
|
||||||
|
parser = OptionParser("usage: %prog ...", version="%prog 1.2")
|
||||||
|
expected_usage = "usage: baz.py ...\n"
|
||||||
|
self.assertUsage(parser, expected_usage)
|
||||||
|
self.assertVersion(parser, "baz.py 1.2")
|
||||||
|
self.assertHelp(parser,
|
||||||
|
expected_usage + "\n" +
|
||||||
|
"options:\n"
|
||||||
|
" --version show program's version number and exit\n"
|
||||||
|
" -h, --help show this help message and exit\n")
|
||||||
|
|
||||||
|
def test_custom_progname(self):
|
||||||
|
parser = OptionParser(prog="thingy",
|
||||||
|
version="%prog 0.1",
|
||||||
|
usage="%prog arg arg")
|
||||||
|
parser.remove_option("-h")
|
||||||
|
parser.remove_option("--version")
|
||||||
|
expected_usage = "usage: thingy arg arg\n"
|
||||||
|
self.assertUsage(parser, expected_usage)
|
||||||
|
self.assertVersion(parser, "thingy 0.1")
|
||||||
|
self.assertHelp(parser, expected_usage + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
class TestExpandDefaults(BaseTest):
|
||||||
|
def setUp(self):
|
||||||
|
self.parser = OptionParser(prog="test")
|
||||||
|
self.help_prefix = """\
|
||||||
|
usage: test [options]
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
"""
|
||||||
|
self.file_help = "read from FILE [default: %default]"
|
||||||
|
self.expected_help_file = self.help_prefix + \
|
||||||
|
" -f FILE, --file=FILE read from FILE [default: foo.txt]\n"
|
||||||
|
self.expected_help_none = self.help_prefix + \
|
||||||
|
" -f FILE, --file=FILE read from FILE [default: none]\n"
|
||||||
|
|
||||||
|
def test_option_default(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
default="foo.txt",
|
||||||
|
help=self.file_help)
|
||||||
|
self.assertHelp(self.parser, self.expected_help_file)
|
||||||
|
|
||||||
|
def test_parser_default_1(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
help=self.file_help)
|
||||||
|
self.parser.set_default('file', "foo.txt")
|
||||||
|
self.assertHelp(self.parser, self.expected_help_file)
|
||||||
|
|
||||||
|
def test_parser_default_2(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
help=self.file_help)
|
||||||
|
self.parser.set_defaults(file="foo.txt")
|
||||||
|
self.assertHelp(self.parser, self.expected_help_file)
|
||||||
|
|
||||||
|
def test_no_default(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
help=self.file_help)
|
||||||
|
self.assertHelp(self.parser, self.expected_help_none)
|
||||||
|
|
||||||
|
def test_default_none_1(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
default=None,
|
||||||
|
help=self.file_help)
|
||||||
|
self.assertHelp(self.parser, self.expected_help_none)
|
||||||
|
|
||||||
|
def test_default_none_2(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
help=self.file_help)
|
||||||
|
self.parser.set_defaults(file=None)
|
||||||
|
self.assertHelp(self.parser, self.expected_help_none)
|
||||||
|
|
||||||
|
def test_float_default(self):
|
||||||
|
self.parser.add_option(
|
||||||
|
"-p", "--prob",
|
||||||
|
help="blow up with probability PROB [default: %default]")
|
||||||
|
self.parser.set_defaults(prob=0.43)
|
||||||
|
expected_help = self.help_prefix + \
|
||||||
|
" -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n"
|
||||||
|
self.assertHelp(self.parser, expected_help)
|
||||||
|
|
||||||
|
def test_alt_expand(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
default="foo.txt",
|
||||||
|
help="read from FILE [default: *DEFAULT*]")
|
||||||
|
self.parser.formatter.default_tag = "*DEFAULT*"
|
||||||
|
self.assertHelp(self.parser, self.expected_help_file)
|
||||||
|
|
||||||
|
def test_no_expand(self):
|
||||||
|
self.parser.add_option("-f", "--file",
|
||||||
|
default="foo.txt",
|
||||||
|
help="read from %default file")
|
||||||
|
self.parser.formatter.default_tag = None
|
||||||
|
expected_help = self.help_prefix + \
|
||||||
|
" -f FILE, --file=FILE read from %default file\n"
|
||||||
|
self.assertHelp(self.parser, expected_help)
|
||||||
|
|
||||||
|
|
||||||
# -- Test parser.parse_args() ------------------------------------------
|
# -- Test parser.parse_args() ------------------------------------------
|
||||||
|
|
||||||
|
@ -318,7 +536,7 @@ class TestStandard(BaseTest):
|
||||||
self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
|
self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
|
||||||
|
|
||||||
def test_required_value(self):
|
def test_required_value(self):
|
||||||
self.assertParseFail(["-a"], "-a option requires a value")
|
self.assertParseFail(["-a"], "-a option requires an argument")
|
||||||
|
|
||||||
def test_invalid_integer(self):
|
def test_invalid_integer(self):
|
||||||
self.assertParseFail(["-b", "5x"],
|
self.assertParseFail(["-b", "5x"],
|
||||||
|
@ -580,7 +798,7 @@ class TestNArgs(BaseTest):
|
||||||
|
|
||||||
def test_nargs_required_values(self):
|
def test_nargs_required_values(self):
|
||||||
self.assertParseFail(["--point", "1.0", "3.5"],
|
self.assertParseFail(["--point", "1.0", "3.5"],
|
||||||
"--point option requires 3 values")
|
"--point option requires 3 arguments")
|
||||||
|
|
||||||
class TestNArgsAppend(BaseTest):
|
class TestNArgsAppend(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -597,7 +815,7 @@ class TestNArgsAppend(BaseTest):
|
||||||
|
|
||||||
def test_nargs_append_required_values(self):
|
def test_nargs_append_required_values(self):
|
||||||
self.assertParseFail(["-f4,3"],
|
self.assertParseFail(["-f4,3"],
|
||||||
"-f option requires 2 values")
|
"-f option requires 2 arguments")
|
||||||
|
|
||||||
def test_nargs_append_simple(self):
|
def test_nargs_append_simple(self):
|
||||||
self.assertParseOK(["--foo=3", "4"],
|
self.assertParseOK(["--foo=3", "4"],
|
||||||
|
@ -612,22 +830,6 @@ class TestVersion(BaseTest):
|
||||||
self.assertStdoutEquals(["--version"], "bar 0.1\n")
|
self.assertStdoutEquals(["--version"], "bar 0.1\n")
|
||||||
sys.argv[0] = oldargv
|
sys.argv[0] = oldargv
|
||||||
|
|
||||||
def test_version_with_prog_keyword(self):
|
|
||||||
oldargv = sys.argv[0]
|
|
||||||
sys.argv[0] = "./foo/bar"
|
|
||||||
self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1",
|
|
||||||
prog="splat")
|
|
||||||
self.assertStdoutEquals(["--version"], "splat 0.1\n")
|
|
||||||
sys.argv[0] = oldargv
|
|
||||||
|
|
||||||
def test_version_with_prog_attribute(self):
|
|
||||||
oldargv = sys.argv[0]
|
|
||||||
sys.argv[0] = "./foo/bar"
|
|
||||||
self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1")
|
|
||||||
self.parser.prog = "splat"
|
|
||||||
self.assertStdoutEquals(["--version"], "splat 0.1\n")
|
|
||||||
sys.argv[0] = oldargv
|
|
||||||
|
|
||||||
def test_no_version(self):
|
def test_no_version(self):
|
||||||
self.parser = OptionParser(usage=SUPPRESS_USAGE)
|
self.parser = OptionParser(usage=SUPPRESS_USAGE)
|
||||||
self.assertParseFail(["--version"],
|
self.assertParseFail(["--version"],
|
||||||
|
@ -673,8 +875,8 @@ class TestOptionGroup(BaseTest):
|
||||||
def test_add_group_wrong_parser(self):
|
def test_add_group_wrong_parser(self):
|
||||||
group = OptionGroup(self.parser, "Spam")
|
group = OptionGroup(self.parser, "Spam")
|
||||||
group.parser = OptionParser()
|
group.parser = OptionParser()
|
||||||
self.assertRaises(self.parser.add_option_group, ValueError,
|
self.assertRaises(self.parser.add_option_group, (group,), None,
|
||||||
"invalid OptionGroup (wrong parser)", funcargs=[group])
|
ValueError, "invalid OptionGroup (wrong parser)")
|
||||||
|
|
||||||
def test_group_manipulate(self):
|
def test_group_manipulate(self):
|
||||||
group = self.parser.add_option_group("Group 2",
|
group = self.parser.add_option_group("Group 2",
|
||||||
|
@ -794,7 +996,22 @@ class TestCallback(BaseTest):
|
||||||
{'filename': "foo", 'x': 42},
|
{'filename': "foo", 'x': 42},
|
||||||
[])
|
[])
|
||||||
|
|
||||||
class TestCallBackExtraArgs(BaseTest):
|
def test_callback_help(self):
|
||||||
|
# This test was prompted by SF bug #960515 -- the point is
|
||||||
|
# not to inspect the help text, just to make sure that
|
||||||
|
# format_help() doesn't crash.
|
||||||
|
parser = OptionParser(usage=SUPPRESS_USAGE)
|
||||||
|
parser.remove_option("-h")
|
||||||
|
parser.add_option("-t", "--test", action="callback",
|
||||||
|
callback=lambda: None, type="string",
|
||||||
|
help="foo")
|
||||||
|
|
||||||
|
expected_help = ("options:\n"
|
||||||
|
" -t TEST, --test=TEST foo\n")
|
||||||
|
self.assertHelp(parser, expected_help)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCallbackExtraArgs(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
options = [make_option("-p", "--point", action="callback",
|
options = [make_option("-p", "--point", action="callback",
|
||||||
callback=self.process_tuple,
|
callback=self.process_tuple,
|
||||||
|
@ -819,7 +1036,7 @@ class TestCallBackExtraArgs(BaseTest):
|
||||||
{'points': [(1,2,3), (4,5,6)]},
|
{'points': [(1,2,3), (4,5,6)]},
|
||||||
[])
|
[])
|
||||||
|
|
||||||
class TestCallBackMeddleArgs(BaseTest):
|
class TestCallbackMeddleArgs(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
options = [make_option(str(x), action="callback",
|
options = [make_option(str(x), action="callback",
|
||||||
callback=self.process_n, dest='things')
|
callback=self.process_n, dest='things')
|
||||||
|
@ -848,7 +1065,7 @@ class TestCallBackMeddleArgs(BaseTest):
|
||||||
{'things': [('foo', '--')]},
|
{'things': [('foo', '--')]},
|
||||||
[2])
|
[2])
|
||||||
|
|
||||||
class TestCallBackManyArgs(BaseTest):
|
class TestCallbackManyArgs(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
options = [make_option("-a", "--apple", action="callback", nargs=2,
|
options = [make_option("-a", "--apple", action="callback", nargs=2,
|
||||||
callback=self.process_many, type="string"),
|
callback=self.process_many, type="string"),
|
||||||
|
@ -870,10 +1087,10 @@ class TestCallBackManyArgs(BaseTest):
|
||||||
self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
|
self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
|
||||||
"-b", "1", "2", "3", "--bob", "-666", "42",
|
"-b", "1", "2", "3", "--bob", "-666", "42",
|
||||||
"0"],
|
"0"],
|
||||||
{},
|
{"apple": None, "bob": None},
|
||||||
[])
|
[])
|
||||||
|
|
||||||
class TestCallBackCheckAbbrev(BaseTest):
|
class TestCallbackCheckAbbrev(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.parser = OptionParser()
|
self.parser = OptionParser()
|
||||||
self.parser.add_option("--foo-bar", action="callback",
|
self.parser.add_option("--foo-bar", action="callback",
|
||||||
|
@ -885,7 +1102,7 @@ class TestCallBackCheckAbbrev(BaseTest):
|
||||||
def test_abbrev_callback_expansion(self):
|
def test_abbrev_callback_expansion(self):
|
||||||
self.assertParseOK(["--foo"], {}, [])
|
self.assertParseOK(["--foo"], {}, [])
|
||||||
|
|
||||||
class TestCallBackVarArgs(BaseTest):
|
class TestCallbackVarArgs(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
options = [make_option("-a", type="int", nargs=2, dest="a"),
|
options = [make_option("-a", type="int", nargs=2, dest="a"),
|
||||||
make_option("-b", action="store_true", dest="b"),
|
make_option("-b", action="store_true", dest="b"),
|
||||||
|
@ -950,13 +1167,12 @@ class ConflictBase(BaseTest):
|
||||||
class TestConflict(ConflictBase):
|
class TestConflict(ConflictBase):
|
||||||
"""Use the default conflict resolution for Optik 1.2: error."""
|
"""Use the default conflict resolution for Optik 1.2: error."""
|
||||||
def assert_conflict_error(self, func):
|
def assert_conflict_error(self, func):
|
||||||
err = self.assertRaises(func, OptionConflictError,
|
err = self.assertRaises(
|
||||||
"option -v/--version: conflicting option "
|
func, ("-v", "--version"), {'action' : "callback",
|
||||||
"string(s): -v",
|
|
||||||
funcargs=["-v", "--version"],
|
|
||||||
funckwargs={'action':"callback",
|
|
||||||
'callback' : self.show_version,
|
'callback' : self.show_version,
|
||||||
'help':"show version"})
|
'help' : "show version"},
|
||||||
|
OptionConflictError,
|
||||||
|
"option -v/--version: conflicting option string(s): -v")
|
||||||
|
|
||||||
self.assertEqual(err.msg, "conflicting option string(s): -v")
|
self.assertEqual(err.msg, "conflicting option string(s): -v")
|
||||||
self.assertEqual(err.option_id, "-v/--version")
|
self.assertEqual(err.option_id, "-v/--version")
|
||||||
|
@ -969,9 +1185,9 @@ class TestConflict(ConflictBase):
|
||||||
self.assert_conflict_error(group.add_option)
|
self.assert_conflict_error(group.add_option)
|
||||||
|
|
||||||
def test_no_such_conflict_handler(self):
|
def test_no_such_conflict_handler(self):
|
||||||
self.assertRaises(self.parser.set_conflict_handler, ValueError,
|
self.assertRaises(
|
||||||
"invalid conflict_resolution value 'foo'",
|
self.parser.set_conflict_handler, ('foo',), None,
|
||||||
funcargs=['foo'])
|
ValueError, "invalid conflict_resolution value 'foo'")
|
||||||
|
|
||||||
|
|
||||||
class TestConflictIgnore(ConflictBase):
|
class TestConflictIgnore(ConflictBase):
|
||||||
|
@ -1082,8 +1298,60 @@ options:
|
||||||
|
|
||||||
# -- Other testing. ----------------------------------------------------
|
# -- Other testing. ----------------------------------------------------
|
||||||
|
|
||||||
|
_expected_help_basic = """\
|
||||||
|
usage: bar.py [options]
|
||||||
|
|
||||||
|
options:
|
||||||
|
-a APPLE throw APPLEs at basket
|
||||||
|
-b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
|
||||||
|
evil spirits that cause trouble and mayhem)
|
||||||
|
--foo=FOO store FOO in the foo list for later fooing
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
"""
|
||||||
|
|
||||||
|
_expected_help_long_opts_first = """\
|
||||||
|
usage: bar.py [options]
|
||||||
|
|
||||||
|
options:
|
||||||
|
-a APPLE throw APPLEs at basket
|
||||||
|
--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
|
||||||
|
evil spirits that cause trouble and mayhem)
|
||||||
|
--foo=FOO store FOO in the foo list for later fooing
|
||||||
|
--help, -h show this help message and exit
|
||||||
|
"""
|
||||||
|
|
||||||
|
_expected_help_title_formatter = """\
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
bar.py [options]
|
||||||
|
|
||||||
|
options
|
||||||
|
=======
|
||||||
|
-a APPLE throw APPLEs at basket
|
||||||
|
--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
|
||||||
|
evil spirits that cause trouble and mayhem)
|
||||||
|
--foo=FOO store FOO in the foo list for later fooing
|
||||||
|
--help, -h show this help message and exit
|
||||||
|
"""
|
||||||
|
|
||||||
|
_expected_help_short_lines = """\
|
||||||
|
usage: bar.py [options]
|
||||||
|
|
||||||
|
options:
|
||||||
|
-a APPLE throw APPLEs at basket
|
||||||
|
-b NUM, --boo=NUM shout "boo!" NUM times (in order to
|
||||||
|
frighten away all the evil spirits
|
||||||
|
that cause trouble and mayhem)
|
||||||
|
--foo=FOO store FOO in the foo list for later
|
||||||
|
fooing
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
"""
|
||||||
|
|
||||||
class TestHelp(BaseTest):
|
class TestHelp(BaseTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.parser = self.make_parser(80)
|
||||||
|
|
||||||
|
def make_parser(self, columns):
|
||||||
options = [
|
options = [
|
||||||
make_option("-a", type="string", dest='a',
|
make_option("-a", type="string", dest='a',
|
||||||
metavar="APPLE", help="throw APPLEs at basket"),
|
metavar="APPLE", help="throw APPLEs at basket"),
|
||||||
|
@ -1095,9 +1363,8 @@ class TestHelp(BaseTest):
|
||||||
make_option("--foo", action="append", type="string", dest='foo',
|
make_option("--foo", action="append", type="string", dest='foo',
|
||||||
help="store FOO in the foo list for later fooing"),
|
help="store FOO in the foo list for later fooing"),
|
||||||
]
|
]
|
||||||
|
os.environ['COLUMNS'] = str(columns)
|
||||||
usage = "%prog [options]"
|
return OptionParser(option_list=options)
|
||||||
self.parser = OptionParser(usage=usage, option_list=options)
|
|
||||||
|
|
||||||
def assertHelpEquals(self, expected_output):
|
def assertHelpEquals(self, expected_output):
|
||||||
# This trick is used to make optparse believe bar.py is being executed.
|
# This trick is used to make optparse believe bar.py is being executed.
|
||||||
|
@ -1109,62 +1376,30 @@ class TestHelp(BaseTest):
|
||||||
sys.argv[0] = oldargv
|
sys.argv[0] = oldargv
|
||||||
|
|
||||||
def test_help(self):
|
def test_help(self):
|
||||||
self.assertHelpEquals("""\
|
self.assertHelpEquals(_expected_help_basic)
|
||||||
usage: bar.py [options]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-aAPPLE throw APPLEs at basket
|
|
||||||
-bNUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all
|
|
||||||
the evil spirits that cause trouble and mayhem)
|
|
||||||
--foo=FOO store FOO in the foo list for later fooing
|
|
||||||
-h, --help show this help message and exit
|
|
||||||
""")
|
|
||||||
|
|
||||||
def test_help_old_usage(self):
|
def test_help_old_usage(self):
|
||||||
self.parser.set_usage("usage: %prog [options]")
|
self.parser.set_usage("usage: %prog [options]")
|
||||||
self.assertHelpEquals("""\
|
self.assertHelpEquals(_expected_help_basic)
|
||||||
usage: bar.py [options]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-aAPPLE throw APPLEs at basket
|
|
||||||
-bNUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all
|
|
||||||
the evil spirits that cause trouble and mayhem)
|
|
||||||
--foo=FOO store FOO in the foo list for later fooing
|
|
||||||
-h, --help show this help message and exit
|
|
||||||
""")
|
|
||||||
|
|
||||||
def test_help_long_opts_first(self):
|
def test_help_long_opts_first(self):
|
||||||
self.parser.formatter.short_first = 0
|
self.parser.formatter.short_first = 0
|
||||||
self.assertHelpEquals("""\
|
self.assertHelpEquals(_expected_help_long_opts_first)
|
||||||
usage: bar.py [options]
|
|
||||||
|
|
||||||
options:
|
|
||||||
-aAPPLE throw APPLEs at basket
|
|
||||||
--boo=NUM, -bNUM shout "boo!" NUM times (in order to frighten away all
|
|
||||||
the evil spirits that cause trouble and mayhem)
|
|
||||||
--foo=FOO store FOO in the foo list for later fooing
|
|
||||||
--help, -h show this help message and exit
|
|
||||||
""")
|
|
||||||
|
|
||||||
def test_help_title_formatter(self):
|
def test_help_title_formatter(self):
|
||||||
self.parser.formatter = TitledHelpFormatter()
|
self.parser.formatter = TitledHelpFormatter()
|
||||||
self.assertHelpEquals("""\
|
self.assertHelpEquals(_expected_help_title_formatter)
|
||||||
Usage
|
|
||||||
=====
|
|
||||||
bar.py [options]
|
|
||||||
|
|
||||||
options
|
def test_wrap_columns(self):
|
||||||
=======
|
# Ensure that wrapping respects $COLUMNS environment variable.
|
||||||
-aAPPLE throw APPLEs at basket
|
# Need to reconstruct the parser, since that's the only time
|
||||||
--boo=NUM, -bNUM shout "boo!" NUM times (in order to frighten away all
|
# we look at $COLUMNS.
|
||||||
the evil spirits that cause trouble and mayhem)
|
self.parser = self.make_parser(60)
|
||||||
--foo=FOO store FOO in the foo list for later fooing
|
self.assertHelpEquals(_expected_help_short_lines)
|
||||||
--help, -h show this help message and exit
|
|
||||||
""")
|
|
||||||
|
|
||||||
def test_help_description_groups(self):
|
def test_help_description_groups(self):
|
||||||
self.parser.set_description(
|
self.parser.set_description(
|
||||||
"This is the program description. This program has "
|
"This is the program description for %prog. %prog has "
|
||||||
"an option group as well as single options.")
|
"an option group as well as single options.")
|
||||||
|
|
||||||
group = OptionGroup(
|
group = OptionGroup(
|
||||||
|
@ -1177,21 +1412,26 @@ options
|
||||||
self.assertHelpEquals("""\
|
self.assertHelpEquals("""\
|
||||||
usage: bar.py [options]
|
usage: bar.py [options]
|
||||||
|
|
||||||
This is the program description. This program has an option group as well as
|
This is the program description for bar.py. bar.py has an option group as
|
||||||
single options.
|
well as single options.
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-a APPLE throw APPLEs at basket
|
-a APPLE throw APPLEs at basket
|
||||||
-bNUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all
|
-b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
|
||||||
the evil spirits that cause trouble and mayhem)
|
evil spirits that cause trouble and mayhem)
|
||||||
--foo=FOO store FOO in the foo list for later fooing
|
--foo=FOO store FOO in the foo list for later fooing
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
|
|
||||||
Dangerous Options:
|
Dangerous Options:
|
||||||
Caution: use of these options is at your own risk. It is believed that
|
Caution: use of these options is at your own risk. It is believed
|
||||||
some of them bite.
|
that some of them bite.
|
||||||
|
|
||||||
-g Group option.
|
-g Group option.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestMatchAbbrev(BaseTest):
|
class TestMatchAbbrev(BaseTest):
|
||||||
def test_match_abbrev(self):
|
def test_match_abbrev(self):
|
||||||
self.assertEqual(_match_abbrev("--f",
|
self.assertEqual(_match_abbrev("--f",
|
||||||
|
@ -1205,15 +1445,23 @@ class TestMatchAbbrev(BaseTest):
|
||||||
s = "--f"
|
s = "--f"
|
||||||
wordmap = {"--foz": None, "--foo": None, "--fie": None}
|
wordmap = {"--foz": None, "--foo": None, "--fie": None}
|
||||||
possibilities = ", ".join(wordmap.keys())
|
possibilities = ", ".join(wordmap.keys())
|
||||||
self.assertRaises(_match_abbrev, BadOptionError,
|
self.assertRaises(
|
||||||
"ambiguous option: --f (%s?)" % possibilities,
|
_match_abbrev, (s, wordmap), None,
|
||||||
funcargs=[s, wordmap])
|
BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
|
||||||
|
|
||||||
|
|
||||||
|
def _testclasses():
|
||||||
|
mod = sys.modules[__name__]
|
||||||
|
return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
for testclass in _testclasses():
|
||||||
|
suite.addTest(unittest.makeSuite(testclass))
|
||||||
|
return suite
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
mod = sys.modules[__name__]
|
test_support.run_suite(suite())
|
||||||
test_support.run_unittest(
|
|
||||||
*[getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue