# Python developers: please do not make changes to this file, since
# it is automatically generated from the Optik source code.
-__version__ = "1.4.1+"
+__version__ = "1.5a1"
__all__ = ['Option',
'SUPPRESS_HELP',
'SUPPRESS_USAGE',
- 'STD_HELP_OPTION',
- 'STD_VERSION_OPTION',
'Values',
'OptionContainer',
'OptionGroup',
'BadOptionError']
__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
modification, are permitted provided that the following conditions are
import sys, os
import types
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):
- def __init__ (self, msg):
+ def __init__(self, msg):
self.msg = msg
- def __str__ (self):
+ def __str__(self):
return self.msg
inconsistent arguments.
"""
- def __init__ (self, msg, option):
+ def __init__(self, msg, option):
self.msg = msg
self.option_id = str(option)
- def __str__ (self):
+ def __str__(self):
if self.option_id:
return "option %s: %s" % (self.option_id, self.msg)
else:
formatting help; by default IndentedHelpFormatter is used.
Instance attributes:
+ parser : OptionParser
+ the controlling OptionParser instance
indent_increment : int
the number of columns to indent per nesting level
max_help_position : int
the calculated starting column for option help text;
initially the same as the maximum
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
current indentation level
current_indent : int
current indentation level (in columns)
help_width : int
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").
"""
- def __init__ (self,
- indent_increment,
- max_help_position,
- width,
- short_first):
+ NO_DEFAULT_VALUE = "none"
+
+ def __init__(self,
+ indent_increment,
+ max_help_position,
+ width,
+ short_first):
+ self.parser = None
self.indent_increment = indent_increment
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.current_indent = 0
self.level = 0
- self.help_width = width - max_help_position
+ self.help_width = None # computed later
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 indent (self):
+ 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):
self.current_indent += self.indent_increment
self.level += 1
- def dedent (self):
+ def dedent(self):
self.current_indent -= self.indent_increment
assert self.current_indent >= 0, "Indent decreased below 0."
self.level -= 1
- def format_usage (self, usage):
+ def format_usage(self, usage):
raise NotImplementedError, "subclasses must implement"
- def format_heading (self, heading):
+ def format_heading(self, heading):
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
indent = " "*self.current_indent
- return textwrap.fill(description, desc_width,
+ return textwrap.fill(description,
+ desc_width,
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
- def format_option (self, option):
+ return option.help.replace(self.default_tag, str(default_value))
+
+ def format_option(self, option):
# The help for each option consists of two parts:
# * the opt strings and metavars
# eg. ("-x", or "-fFILENAME, --file=FILENAME")
# -fFILENAME, --file=FILENAME
# read data from FILENAME
result = []
- opts = option.option_strings
+ opts = self.option_strings[option]
opt_width = self.help_position - self.current_indent - 2
if len(opts) > opt_width:
opts = "%*s%s\n" % (self.current_indent, "", opts)
indent_first = 0
result.append(opts)
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.extend(["%*s%s\n" % (self.help_position, "", line)
for line in help_lines[1:]])
result.append("\n")
return "".join(result)
- def store_option_strings (self, parser):
+ def store_option_strings(self, parser):
self.indent()
max_len = 0
for opt in parser.option_list:
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)
self.indent()
for group in parser.option_groups:
for opt in group.option_list:
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)
self.dedent()
self.dedent()
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."""
if option.takes_value():
metavar = option.metavar or option.dest.upper()
- short_opts = [sopt + metavar for sopt in option._short_opts]
- long_opts = [lopt + "=" + metavar for lopt in option._long_opts]
+ short_opts = [self._short_opt_fmt % (sopt, metavar)
+ for sopt in option._short_opts]
+ long_opts = [self._long_opt_fmt % (lopt, metavar)
+ for lopt in option._long_opts]
else:
short_opts = option._short_opts
long_opts = option._long_opts
"""Format help with indented section bodies.
"""
- def __init__ (self,
- indent_increment=2,
- max_help_position=24,
- width=79,
- short_first=1):
+ def __init__(self,
+ indent_increment=2,
+ max_help_position=24,
+ width=None,
+ short_first=1):
HelpFormatter.__init__(
self, indent_increment, max_help_position, width, short_first)
- def format_usage (self, usage):
- return "usage: %s\n" % usage
+ def format_usage(self, usage):
+ return _("usage: %s\n") % usage
- def format_heading (self, heading):
+ def format_heading(self, heading):
return "%*s%s:\n" % (self.current_indent, "", heading)
"""Format help with underlined section headers.
"""
- def __init__ (self,
- indent_increment=0,
- max_help_position=24,
- width=79,
- short_first=0):
+ def __init__(self,
+ indent_increment=0,
+ max_help_position=24,
+ width=None,
+ short_first=0):
HelpFormatter.__init__ (
self, indent_increment, max_help_position, width, short_first)
- def format_usage (self, usage):
- return "%s %s\n" % (self.format_heading("Usage"), usage)
+ def format_usage(self, 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))
-_builtin_cvt = { "int" : (int, "integer"),
- "long" : (long, "long integer"),
- "float" : (float, "floating-point"),
- "complex" : (complex, "complex") }
+_builtin_cvt = { "int" : (int, _("integer")),
+ "long" : (long, _("long integer")),
+ "float" : (float, _("floating-point")),
+ "complex" : (complex, _("complex")) }
-def check_builtin (option, opt, value):
+def check_builtin(option, opt, value):
(cvt, what) = _builtin_cvt[option.type]
try:
return cvt(value)
except ValueError:
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):
if value in option.choices:
else:
choices = ", ".join(map(repr, option.choices))
raise OptionValueError(
- "option %s: invalid choice: %r (choose from %s)"
+ _("option %s: invalid choice: %r (choose from %s)")
% (opt, value, choices))
# Not supplying a default is different from a default of None,
# so we need an explicit "not supplied" value.
-NO_DEFAULT = "NO"+"DEFAULT"
+NO_DEFAULT = ("NO", "DEFAULT")
class Option:
TYPE_CHECKER = { "int" : check_builtin,
"long" : check_builtin,
"float" : check_builtin,
- "complex" : check_builtin,
+ "complex": check_builtin,
"choice" : check_choice,
}
# -- Constructor/initialization methods ----------------------------
- def __init__ (self, *opts, **attrs):
+ def __init__(self, *opts, **attrs):
# Set _short_opts, _long_opts attrs from 'opts' tuple.
# Have to be set now, in case no option strings are supplied.
self._short_opts = []
for checker in self.CHECK_METHODS:
checker(self)
- def _check_opt_strings (self, opts):
+ def _check_opt_strings(self, opts):
# Filter out None because early versions of Optik had exactly
# one short option and one long option, either of which
# could be None.
raise TypeError("at least one option string must be supplied")
return opts
- def _set_opt_strings (self, opts):
+ def _set_opt_strings(self, opts):
for opt in opts:
if len(opt) < 2:
raise OptionError(
self)
self._long_opts.append(opt)
- def _set_attrs (self, attrs):
+ def _set_attrs(self, attrs):
for attr in self.ATTRS:
if attrs.has_key(attr):
setattr(self, attr, attrs[attr])
# -- Constructor validation methods --------------------------------
- def _check_action (self):
+ def _check_action(self):
if self.action is None:
self.action = "store"
elif self.action not in self.ACTIONS:
raise OptionError("invalid action: %r" % self.action, self)
- def _check_type (self):
+ def _check_type(self):
if self.type is None:
# XXX should factor out another class attr here: list of
# actions that *require* a type
# No type given? "string" is the most sensible default.
self.type = "string"
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:
raise OptionError("invalid option type: %r" % self.type, self)
if self.action not in self.TYPED_ACTIONS:
raise OptionError(
"must not supply choices for type %r" % self.type, 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.
+ def _check_dest(self):
+ # No destination given, and we need one for this action. The
+ # 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,
# or from the first short option string if no long options.
if self._long_opts:
else:
self.dest = self._short_opts[0][1]
- def _check_const (self):
+ def _check_const(self):
if self.action != "store_const" and self.const is not None:
raise OptionError(
"'const' must not be supplied for action %r" % self.action,
self)
- def _check_nargs (self):
+ def _check_nargs(self):
if self.action in self.TYPED_ACTIONS:
if self.nargs is None:
self.nargs = 1
"'nargs' must not be supplied for action %r" % self.action,
self)
- def _check_callback (self):
+ def _check_callback(self):
if self.action == "callback":
if not callable(self.callback):
raise OptionError(
# -- Miscellaneous methods -----------------------------------------
- def __str__ (self):
+ def __str__(self):
return "/".join(self._short_opts + self._long_opts)
- def takes_value (self):
+ __repr__ = _repr
+
+ def takes_value(self):
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 --------------------------------------------
- def check_value (self, opt, value):
+ def check_value(self, opt, value):
checker = self.TYPE_CHECKER.get(self.type)
if checker is None:
return value
else:
return checker(self, opt, value)
- def process (self, opt, value, values, parser):
-
- # First, convert the value(s) to the right type. Howl if any
- # value(s) are bogus.
+ def convert_value(self, opt, value):
if value is not None:
if self.nargs == 1:
- value = self.check_value(opt, value)
+ return self.check_value(opt, value)
else:
- value = tuple([self.check_value(opt, v) for v in value])
+ return tuple([self.check_value(opt, v) for v in value])
+
+ def process(self, opt, value, values, parser):
+
+ # First, convert the value(s) to the right type. Howl if any
+ # value(s) are bogus.
+ value = self.convert_value(opt, value)
# And then take whatever action is expected of us.
# This is a separate method to make life easier for
return self.take_action(
self.action, self.dest, opt, value, values, parser)
- def take_action (self, action, dest, opt, value, values, parser):
+ def take_action(self, action, dest, opt, value, values, parser):
if action == "store":
setattr(values, dest, value)
elif action == "store_const":
# class Option
-def get_prog_name ():
- return os.path.basename(sys.argv[0])
-
-
SUPPRESS_HELP = "SUPPRESS"+"HELP"
SUPPRESS_USAGE = "SUPPRESS"+"USAGE"
-STD_HELP_OPTION = Option("-h", "--help",
- action="help",
- help="show this help message and exit")
-STD_VERSION_OPTION = Option("--version",
- action="version",
- help="show program's version number and exit")
+# For compatibility with Python 2.2
+try:
+ True, False
+except NameError:
+ (True, False) = (1, 0)
+try:
+ basestring
+except NameError:
+ basestring = (str, unicode)
class Values:
- def __init__ (self, defaults=None):
+ def __init__(self, defaults=None):
if defaults:
for (attr, val) in defaults.items():
setattr(self, attr, val)
- def __repr__ (self):
- return ("<%s at 0x%x: %r>"
- % (self.__class__.__name__, id(self), self.__dict__))
+ def __str__(self):
+ return str(self.__dict__)
+
+ __repr__ = _repr
- def _update_careful (self, dict):
+ 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):
"""
Update the option values from an arbitrary dictionary, but only
use keys from dict that already have a corresponding attribute
if dval is not None:
setattr(self, attr, dval)
- def _update_loose (self, dict):
+ def _update_loose(self, dict):
"""
Update the option values from an arbitrary dictionary,
using all keys from the dictionary regardless of whether
"""
self.__dict__.update(dict)
- def _update (self, dict, mode):
+ def _update(self, dict, mode):
if mode == "careful":
self._update_careful(dict)
elif mode == "loose":
else:
raise ValueError, "invalid update mode: %r" % mode
- def read_module (self, modname, mode="careful"):
+ def read_module(self, modname, mode="careful"):
__import__(modname)
mod = sys.modules[modname]
self._update(vars(mod), mode)
- def read_file (self, filename, mode="careful"):
+ def read_file(self, filename, mode="careful"):
vars = {}
execfile(filename, vars)
self._update(vars, mode)
- def ensure_value (self, attr, value):
+ def ensure_value(self, attr, value):
if not hasattr(self, attr) or getattr(self, attr) is None:
setattr(self, attr, value)
return getattr(self, attr)
"""
- def __init__ (self, option_class, conflict_handler, description):
+ def __init__(self, option_class, conflict_handler, description):
# Initialize the option list and related data structures.
# This method must be provided by subclasses, and it must
# initialize at least the following instance attributes:
self.set_conflict_handler(conflict_handler)
self.set_description(description)
- def _create_option_mappings (self):
+ def _create_option_mappings(self):
# For use by OptionParser constructor -- create the master
# option mappings used by this OptionParser and all
# OptionGroups that it owns.
self.defaults = {} # maps option dest -> default value
- def _share_option_mappings (self, parser):
+ def _share_option_mappings(self, parser):
# For use by OptionGroup constructor -- use shared option
# mappings from the OptionParser that owns this OptionGroup.
self._short_opt = parser._short_opt
self._long_opt = parser._long_opt
self.defaults = parser.defaults
- def set_conflict_handler (self, handler):
+ def set_conflict_handler(self, handler):
if handler not in ("ignore", "error", "resolve"):
raise ValueError, "invalid conflict_resolution value %r" % handler
self.conflict_handler = handler
- def set_description (self, description):
+ def set_description(self, description):
self.description = description
+ def get_description(self):
+ return self.description
+
# -- Option-adding methods -----------------------------------------
- def _check_conflict (self, option):
+ def _check_conflict(self, option):
conflict_opts = []
for opt in option._short_opts:
if self._short_opt.has_key(opt):
if not (c_option._short_opts or c_option._long_opts):
c_option.container.option_list.remove(c_option)
- def add_option (self, *args, **kwargs):
+ def add_option(self, *args, **kwargs):
"""add_option(Option)
add_option(opt_str, ..., kwarg=val, ...)
"""
return option
- def add_options (self, option_list):
+ def add_options(self, option_list):
for option in option_list:
self.add_option(option)
# -- Option query/removal methods ----------------------------------
- def get_option (self, opt_str):
+ def get_option(self, opt_str):
return (self._short_opt.get(opt_str) or
self._long_opt.get(opt_str))
- def has_option (self, opt_str):
+ def has_option(self, opt_str):
return (self._short_opt.has_key(opt_str) or
self._long_opt.has_key(opt_str))
- def remove_option (self, opt_str):
+ def remove_option(self, opt_str):
option = self._short_opt.get(opt_str)
if option is None:
option = self._long_opt.get(opt_str)
# -- Help-formatting methods ---------------------------------------
- def format_option_help (self, formatter):
+ def format_option_help(self, formatter):
if not self.option_list:
return ""
result = []
result.append(formatter.format_option(option))
return "".join(result)
- def format_description (self, formatter):
- if self.description:
- return formatter.format_description(self.description)
- else:
- return ""
+ def format_description(self, formatter):
+ return formatter.format_description(self.get_description())
- def format_help (self, formatter):
+ def format_help(self, formatter):
+ result = []
if self.description:
- desc = self.format_description(formatter) + "\n"
- else:
- desc = ""
- return desc + self.format_option_help(formatter)
+ result.append(self.format_description(formatter))
+ if self.option_list:
+ result.append(self.format_option_help(formatter))
+ return "\n".join(result)
class OptionGroup (OptionContainer):
- def __init__ (self, parser, title, description=None):
+ def __init__(self, parser, title, description=None):
self.parser = parser
OptionContainer.__init__(
self, parser.option_class, parser.conflict_handler, description)
self.title = title
- def _create_option_list (self):
+ def _create_option_list(self):
self.option_list = []
self._share_option_mappings(self.parser)
- def set_title (self, title):
+ def set_title(self, title):
self.title = title
# -- Help-formatting methods ---------------------------------------
- def format_help (self, formatter):
+ def format_help(self, formatter):
result = formatter.format_heading(self.title)
formatter.indent()
result += OptionContainer.format_help(self, formatter)
the name of the current program (to override
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.
Assuming -a and -b each take a single argument, the command-line
-ablah foo bar -bboo baz
Python's getopt module, Perl's Getopt::Std, and other argument-
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]
the argument list currently being parsed. Only set when
parse_args() is active, and continually trimmed down as
standard_option_list = []
- def __init__ (self,
- usage=None,
- option_list=None,
- option_class=Option,
- version=None,
- conflict_handler="error",
- description=None,
- formatter=None,
- add_help_option=1,
- prog=None):
+ def __init__(self,
+ usage=None,
+ option_list=None,
+ option_class=Option,
+ version=None,
+ conflict_handler="error",
+ description=None,
+ formatter=None,
+ add_help_option=True,
+ prog=None):
OptionContainer.__init__(
self, option_class, conflict_handler, description)
self.set_usage(usage)
self.prog = prog
self.version = version
- self.allow_interspersed_args = 1
+ self.allow_interspersed_args = True
+ self.process_default_values = True
if formatter is None:
formatter = IndentedHelpFormatter()
self.formatter = formatter
+ self.formatter.set_parser(self)
# Populate the option list; initial sources are the
# standard_option_list class attribute, the 'option_list'
- # argument, and the STD_VERSION_OPTION (if 'version' supplied)
- # and STD_HELP_OPTION globals.
+ # argument, and (if applicable) the _add_version_option() and
+ # _add_help_option() methods.
self._populate_option_list(option_list,
add_help=add_help_option)
# -- Private methods -----------------------------------------------
# (used by our or OptionContainer's constructor)
- def _create_option_list (self):
+ def _create_option_list(self):
self.option_list = []
self.option_groups = []
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:
self.add_options(self.standard_option_list)
if option_list:
self.add_options(option_list)
if self.version:
- self.add_option(STD_VERSION_OPTION)
+ self._add_version_option()
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.
self.rargs = None
self.largs = None
self.values = None
- def _get_prog_name(self):
- if self.prog:
- return self.prog
- else:
- return get_prog_name()
# -- Simple modifier methods ---------------------------------------
- def set_usage (self, usage):
+ def set_usage(self, usage):
if usage is None:
- self.usage = "%prog [options]"
+ self.usage = _("%prog [options]")
elif usage is SUPPRESS_USAGE:
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:]
else:
self.usage = usage
- def enable_interspersed_args (self):
- self.allow_interspersed_args = 1
+ def enable_interspersed_args(self):
+ self.allow_interspersed_args = True
+
+ def disable_interspersed_args(self):
+ self.allow_interspersed_args = False
- def disable_interspersed_args (self):
- self.allow_interspersed_args = 0
+ 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
- def set_defaults (self, **kwargs):
+ def set_defaults(self, **kwargs):
self.defaults.update(kwargs)
- def get_default_values (self):
- return Values(self.defaults)
+ 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):
+ if not self.process_default_values:
+ # Old, pre-Optik 1.5 behaviour.
+ 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 -------------------------------------------
- def add_option_group (self, *args, **kwargs):
+ def add_option_group(self, *args, **kwargs):
# XXX lots of overlap with OptionContainer.add_option()
if type(args[0]) is types.StringType:
group = OptionGroup(self, *args, **kwargs)
self.option_groups.append(group)
return group
- def get_option_group (self, opt_str):
+ def get_option_group(self, opt_str):
option = (self._short_opt.get(opt_str) or
self._long_opt.get(opt_str))
if option and option.container is not self:
# -- Option-parsing methods ----------------------------------------
- def _get_args (self, args):
+ def _get_args(self, args):
if args is None:
return sys.argv[1:]
else:
return args[:] # don't modify caller's list
- def parse_args (self, args=None, values=None):
+ def parse_args(self, args=None, values=None):
"""
parse_args(args : [string] = sys.argv[1:],
values : Values = None)
args = largs + rargs
return self.check_values(values, args)
- def check_values (self, values, args):
+ def check_values(self, values, args):
"""
check_values(values : Values, args : [string])
-> (values : Values, args : [string])
"""
return (values, args)
- def _process_args (self, largs, rargs, values):
+ def _process_args(self, largs, rargs, values):
"""_process_args(largs : [string],
rargs : [string],
values : Values)
# *empty* -- still a subset of [arg0, ..., arg(i-1)], but
# not a very interesting subset!
- def _match_long_opt (self, opt):
+ def _match_long_opt(self, opt):
"""_match_long_opt(opt : string) -> string
Determine which long option string 'opt' matches, ie. which one
"""
return _match_abbrev(opt, self._long_opt)
- def _process_long_opt (self, rargs, values):
+ def _process_long_opt(self, rargs, values):
arg = rargs.pop(0)
# Value explicitly attached to arg? Pretend it's the next
if "=" in arg:
(opt, next_arg) = arg.split("=", 1)
rargs.insert(0, next_arg)
- had_explicit_value = 1
+ had_explicit_value = True
else:
opt = arg
- had_explicit_value = 0
+ had_explicit_value = False
opt = self._match_long_opt(opt)
option = self._long_opt[opt]
nargs = option.nargs
if len(rargs) < nargs:
if nargs == 1:
- self.error("%s option requires a value" % opt)
+ self.error(_("%s option requires an argument") % opt)
else:
- self.error("%s option requires %d values"
+ self.error(_("%s option requires %d arguments")
% (opt, nargs))
elif nargs == 1:
value = rargs.pop(0)
del rargs[0:nargs]
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:
value = None
option.process(opt, value, values, self)
- def _process_short_opts (self, rargs, values):
+ def _process_short_opts(self, rargs, values):
arg = rargs.pop(0)
- stop = 0
+ stop = False
i = 1
for ch in arg[1:]:
opt = "-" + ch
i += 1 # we have consumed a character
if not option:
- self.error("no such option: %s" % opt)
+ self.error(_("no such option: %s") % opt)
if option.takes_value():
# Any characters left in arg? Pretend they're the
# next arg, and stop consuming characters of arg.
if i < len(arg):
rargs.insert(0, arg[i:])
- stop = 1
+ stop = True
nargs = option.nargs
if len(rargs) < nargs:
if nargs == 1:
- self.error("%s option requires a value" % opt)
+ self.error(_("%s option requires an argument") % opt)
else:
- self.error("%s option requires %s values"
+ self.error(_("%s option requires %d arguments")
% (opt, nargs))
elif nargs == 1:
value = rargs.pop(0)
# -- Feedback methods ----------------------------------------------
- def error (self, msg):
+ 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):
"""error(msg : string)
Print a usage message incorporating 'msg' to stderr and exit.
should either exit or raise an exception.
"""
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:
return self.formatter.format_usage(
- self.usage.replace("%prog", self._get_prog_name()))
+ self.expand_prog_name(self.usage))
else:
return ""
- def print_usage (self, file=None):
+ def print_usage(self, file=None):
"""print_usage(file : file = stdout)
Print the usage message for the current program (self.usage) to
if self.usage:
print >>file, self.get_usage()
- def get_version (self):
+ def get_version(self):
if self.version:
- return self.version.replace("%prog", self._get_prog_name())
+ return self.expand_prog_name(self.version)
else:
return ""
- def print_version (self, file=None):
+ def print_version(self, file=None):
"""print_version(file : file = stdout)
Print the version message for this program (self.version) to
if self.version:
print >>file, self.get_version()
- def format_option_help (self, formatter=None):
+ def format_option_help(self, formatter=None):
if formatter is None:
formatter = self.formatter
formatter.store_option_strings(self)
result = []
- result.append(formatter.format_heading("options"))
+ result.append(formatter.format_heading(_("options")))
formatter.indent()
if self.option_list:
result.append(OptionContainer.format_option_help(self, formatter))
# Drop the last "\n", or the header if no options or option groups:
return "".join(result[:-1])
- def format_help (self, formatter=None):
+ def format_help(self, formatter=None):
if formatter is None:
formatter = self.formatter
result = []
result.append(self.format_option_help(formatter))
return "".join(result)
- def print_help (self, file=None):
+ def print_help(self, file=None):
"""print_help(file : file = stdout)
Print an extended help message, listing all options and any
# class OptionParser
-def _match_abbrev (s, wordmap):
+def _match_abbrev(s, wordmap):
"""_match_abbrev(s : string, wordmap : {string : Option}) -> string
Return the string key in 'wordmap' for which 's' is an unambiguous
if len(possibilities) == 1:
return possibilities[0]
elif not possibilities:
- raise BadOptionError("no such option: %s" % s)
+ raise BadOptionError(_("no such option: %s") % s)
else:
# More than one possible completion: ambiguous prefix.
- raise BadOptionError("ambiguous option: %s (%s?)"
+ raise BadOptionError(_("ambiguous option: %s (%s?)")
% (s, ", ".join(possibilities)))
from optparse import make_option, Option, IndentedHelpFormatter, \
TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
- BadOptionError, OptionValueError
-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)
+ BadOptionError, OptionValueError, _match_abbrev
class BaseTest(unittest.TestCase):
def assertParseOK(self, args, expected_opts, expected_positional_args):
return (options, positional_args)
- def assertRaises(self, func, expected_exception, expected_output,
- get_output=None,
- funcargs=[], funckwargs={}):
+ def assertRaises(self,
+ func,
+ args,
+ kwargs,
+ expected_exception,
+ expected_output,
+ get_output=None,
+ exact_match=False):
"""Assert the expected exception is raised when calling a function.
Also check whether the right error message is given for a given error.
- Keyword arguments:
- func -- The function to be called.
- expected_exception -- The exception that should be raised.
- expected_output -- The output we expect to see.
- get_output -- The function to call to get the output.
- funcargs -- The arguments `func` should be called with.
- funckwargs -- The keyword arguments `func` should be called with.
+ Arguments:
+ func -- the function to call
+ args -- positional arguments to `func`
+ kwargs -- keyword arguments to `func`
+ expected_exception -- exception that should be raised
+ expected_output -- output we expect to see
+ 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.
"""
+ if args is None:
+ args = ()
+ if kwargs is None:
+ kwargs = {}
if get_output is None:
get_output = self.exception
try:
- out = func(*funcargs, **funckwargs)
+ out = func(*args, **kwargs)
except expected_exception, err:
- output = get_output(err)
-
- self.failUnless(output.find(expected_output) != -1,
- """
-Message was:
-%(output)s
-Should contain:
-%(expected_output)s
-Function called:
-%(func)s
-With args/kwargs:
-%(funcargs)s/%(funckwargs)s""" % locals())
+ actual_output = get_output(err)
+
+ if exact_match:
+ match = actual_output == expected_exception
+ else:
+ match = actual_output.find(expected_output) != -1
+
+ self.assert_(match,
+ """mismatched output
+expected output:
+'''%(expected_output)s'''
+actual output:
+'''%(actual_output)s'''
+""" % locals())
return err
else:
- self.fail("""
-No %(expected_exception)s raised.
-Function called:
-%(func)s
-With args/kwargs:
-%(funcargs)s/%(funckwargs)s""" % locals ())
+ self.fail("""expected exception %(expected_exception)s not raised
+called %(func)r
+with args %(args)r
+and kwargs %(kwargs)r
+""" % locals ())
# -- Functions to be used as the get_output argument to assertRaises ------
def redirected_stdout(self, err):
return sys.stdout.getvalue()
+ def redirected_stderr(self, err):
+ return sys.stderr.getvalue()
+
# -- Assertions used in more than one class --------------------
def assertParseFail(self, cmdline_args, expected_output):
"""Assert the parser fails with the expected message."""
- self.assertRaises(self.parser.parse_args, SystemExit, expected_output,
- funcargs=[cmdline_args])
+ sys.stderr = StringIO()
+ 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):
"""Assert the parser prints the expected output on stdout."""
sys.stdout = StringIO()
- self.assertRaises(self.parser.parse_args, SystemExit, expected_output,
- self.redirected_stdout, [cmdline_args])
+ self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
+ SystemExit, expected_output,
+ self.redirected_stdout)
sys.stdout = sys.__stdout__
def assertTypeError(self, func, expected_output, *args):
"""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 -------------------------------------
self.parser = OptionParser(usage=SUPPRESS_USAGE)
def assertOptionError(self, expected_output, args=[], kwargs={}):
- self.assertRaises(make_option, OptionError, expected_output,
- funcargs=args, funckwargs=kwargs)
+ self.assertRaises(make_option, args, kwargs,
+ OptionError, expected_output)
def test_opt_string_empty(self):
self.assertTypeError(make_option,
def test_type_invalid(self):
self.assertOptionError("invalid option type: 'foo'",
["-b"], {'type': 'foo'})
+ self.assertOptionError("invalid option type: 'tuple'",
+ ["-b"], {'type': tuple})
def test_no_type_for_action(self):
self.assertOptionError("must not supply a type for action 'count'",
self.assert_removed()
def test_remove_nonexistent(self):
- self.assertRaises(self.parser.remove_option, ValueError,
- "no such option 'foo'", funcargs=['foo'])
+ self.assertRaises(self.parser.remove_option, ('foo',), None,
+ 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() ------------------------------------------
self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
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):
self.assertParseFail(["-b", "5x"],
def test_nargs_required_values(self):
self.assertParseFail(["--point", "1.0", "3.5"],
- "--point option requires 3 values")
+ "--point option requires 3 arguments")
class TestNArgsAppend(BaseTest):
def setUp(self):
def test_nargs_append_required_values(self):
self.assertParseFail(["-f4,3"],
- "-f option requires 2 values")
+ "-f option requires 2 arguments")
def test_nargs_append_simple(self):
self.assertParseOK(["--foo=3", "4"],
self.assertStdoutEquals(["--version"], "bar 0.1\n")
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):
self.parser = OptionParser(usage=SUPPRESS_USAGE)
self.assertParseFail(["--version"],
def test_add_group_wrong_parser(self):
group = OptionGroup(self.parser, "Spam")
group.parser = OptionParser()
- self.assertRaises(self.parser.add_option_group, ValueError,
- "invalid OptionGroup (wrong parser)", funcargs=[group])
+ self.assertRaises(self.parser.add_option_group, (group,), None,
+ ValueError, "invalid OptionGroup (wrong parser)")
def test_group_manipulate(self):
group = self.parser.add_option_group("Group 2",
{'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):
options = [make_option("-p", "--point", action="callback",
callback=self.process_tuple,
{'points': [(1,2,3), (4,5,6)]},
[])
-class TestCallBackMeddleArgs(BaseTest):
+class TestCallbackMeddleArgs(BaseTest):
def setUp(self):
options = [make_option(str(x), action="callback",
callback=self.process_n, dest='things')
{'things': [('foo', '--')]},
[2])
-class TestCallBackManyArgs(BaseTest):
+class TestCallbackManyArgs(BaseTest):
def setUp(self):
options = [make_option("-a", "--apple", action="callback", nargs=2,
callback=self.process_many, type="string"),
self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
"-b", "1", "2", "3", "--bob", "-666", "42",
"0"],
- {},
+ {"apple": None, "bob": None},
[])
-class TestCallBackCheckAbbrev(BaseTest):
+class TestCallbackCheckAbbrev(BaseTest):
def setUp(self):
self.parser = OptionParser()
self.parser.add_option("--foo-bar", action="callback",
def test_abbrev_callback_expansion(self):
self.assertParseOK(["--foo"], {}, [])
-class TestCallBackVarArgs(BaseTest):
+class TestCallbackVarArgs(BaseTest):
def setUp(self):
options = [make_option("-a", type="int", nargs=2, dest="a"),
make_option("-b", action="store_true", dest="b"),
class TestConflict(ConflictBase):
"""Use the default conflict resolution for Optik 1.2: error."""
def assert_conflict_error(self, func):
- err = self.assertRaises(func, OptionConflictError,
- "option -v/--version: conflicting option "
- "string(s): -v",
- funcargs=["-v", "--version"],
- funckwargs={'action':"callback",
- 'callback':self.show_version,
- 'help':"show version"})
+ err = self.assertRaises(
+ func, ("-v", "--version"), {'action' : "callback",
+ 'callback' : self.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.option_id, "-v/--version")
self.assert_conflict_error(group.add_option)
def test_no_such_conflict_handler(self):
- self.assertRaises(self.parser.set_conflict_handler, ValueError,
- "invalid conflict_resolution value 'foo'",
- funcargs=['foo'])
+ self.assertRaises(
+ self.parser.set_conflict_handler, ('foo',), None,
+ ValueError, "invalid conflict_resolution value 'foo'")
class TestConflictIgnore(ConflictBase):
# -- 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):
def setUp(self):
+ self.parser = self.make_parser(80)
+
+ def make_parser(self, columns):
options = [
make_option("-a", type="string", dest='a',
metavar="APPLE", help="throw APPLEs at basket"),
make_option("--foo", action="append", type="string", dest='foo',
help="store FOO in the foo list for later fooing"),
]
-
- usage = "%prog [options]"
- self.parser = OptionParser(usage=usage, option_list=options)
+ os.environ['COLUMNS'] = str(columns)
+ return OptionParser(option_list=options)
def assertHelpEquals(self, expected_output):
# This trick is used to make optparse believe bar.py is being executed.
sys.argv[0] = oldargv
def test_help(self):
- self.assertHelpEquals("""\
-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
-""")
+ self.assertHelpEquals(_expected_help_basic)
def test_help_old_usage(self):
self.parser.set_usage("usage: %prog [options]")
- self.assertHelpEquals("""\
-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
-""")
+ self.assertHelpEquals(_expected_help_basic)
def test_help_long_opts_first(self):
self.parser.formatter.short_first = 0
- self.assertHelpEquals("""\
-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
-""")
+ self.assertHelpEquals(_expected_help_long_opts_first)
def test_help_title_formatter(self):
self.parser.formatter = TitledHelpFormatter()
- self.assertHelpEquals("""\
-Usage
-=====
- bar.py [options]
+ self.assertHelpEquals(_expected_help_title_formatter)
-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_wrap_columns(self):
+ # Ensure that wrapping respects $COLUMNS environment variable.
+ # Need to reconstruct the parser, since that's the only time
+ # we look at $COLUMNS.
+ self.parser = self.make_parser(60)
+ self.assertHelpEquals(_expected_help_short_lines)
def test_help_description_groups(self):
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.")
group = OptionGroup(
self.assertHelpEquals("""\
usage: bar.py [options]
-This is the program description. This program has an option group as well as
-single options.
+This is the program description for bar.py. bar.py has an option group as
+well as single 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
+ -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
Dangerous Options:
- Caution: use of these options is at your own risk. It is believed that
- some of them bite.
- -g Group option.
+ Caution: use of these options is at your own risk. It is believed
+ that some of them bite.
+
+ -g Group option.
""")
+
+
+
class TestMatchAbbrev(BaseTest):
def test_match_abbrev(self):
self.assertEqual(_match_abbrev("--f",
s = "--f"
wordmap = {"--foz": None, "--foo": None, "--fie": None}
possibilities = ", ".join(wordmap.keys())
- self.assertRaises(_match_abbrev, BadOptionError,
- "ambiguous option: --f (%s?)" % possibilities,
- funcargs=[s, wordmap])
+ self.assertRaises(
+ _match_abbrev, (s, wordmap), None,
+ BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
-def test_main():
+
+def _testclasses():
mod = sys.modules[__name__]
- test_support.run_unittest(
- *[getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
- )
+ 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():
+ test_support.run_suite(suite())
if __name__ == '__main__':
unittest.main()