Update optparse to Optik 1.5.1.
diff --git a/Lib/optparse.py b/Lib/optparse.py
index ae3d00d..f4c2c70 100644
--- a/Lib/optparse.py
+++ b/Lib/optparse.py
@@ -16,7 +16,7 @@
# Python developers: please do not make changes to this file, since
# it is automatically generated from the Optik source code.
-__version__ = "1.5a2"
+__version__ = "1.5.1"
__all__ = ['Option',
'SUPPRESS_HELP',
@@ -35,8 +35,8 @@
'BadOptionError']
__copyright__ = """
-Copyright (c) 2001-2004 Gregory P. Ward. All rights reserved.
-Copyright (c) 2002-2004 Python Software Foundation. All rights reserved.
+Copyright (c) 2001-2006 Gregory P. Ward. All rights reserved.
+Copyright (c) 2002-2006 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
@@ -67,21 +67,26 @@
"""
import sys, os
+import types
import textwrap
-try:
- from gettext import gettext as _
-except ImportError:
- _ = lambda arg: arg
def _repr(self):
return "<%s at 0x%x: %s>" % (self.__class__.__name__, id(self), self)
# This file was generated from:
-# Id: option_parser.py 421 2004-10-26 00:45:16Z greg
-# Id: option.py 422 2004-10-26 00:53:47Z greg
-# Id: help.py 367 2004-07-24 23:21:21Z gward
-# Id: errors.py 367 2004-07-24 23:21:21Z gward
+# Id: option_parser.py 509 2006-04-20 00:58:24Z gward
+# Id: option.py 509 2006-04-20 00:58:24Z gward
+# Id: help.py 509 2006-04-20 00:58:24Z gward
+# Id: errors.py 509 2006-04-20 00:58:24Z gward
+
+try:
+ from gettext import gettext
+except ImportError:
+ def gettext(message):
+ return message
+_ = gettext
+
class OptParseError (Exception):
def __init__(self, msg):
@@ -120,8 +125,25 @@
class BadOptionError (OptParseError):
"""
- Raised if an invalid or ambiguous option is seen on the command-line.
+ Raised if an invalid option is seen on the command line.
"""
+ def __init__(self, opt_str):
+ self.opt_str = opt_str
+
+ def __str__(self):
+ return _("no such option: %s") % self.opt_str
+
+class AmbiguousOptionError (BadOptionError):
+ """
+ Raised if an ambiguous option is seen on the command line.
+ """
+ def __init__(self, opt_str, possibilities):
+ BadOptionError.__init__(self, opt_str)
+ self.possibilities = possibilities
+
+ def __str__(self):
+ return (_("ambiguous option: %s (%s?)")
+ % (self.opt_str, ", ".join(self.possibilities)))
class HelpFormatter:
@@ -223,15 +245,30 @@
def format_heading(self, heading):
raise NotImplementedError, "subclasses must implement"
- def format_description(self, description):
- if not description:
- return ""
- desc_width = self.width - self.current_indent
+ def _format_text(self, text):
+ """
+ Format a paragraph of free-form text for inclusion in the
+ help output at the current indentation level.
+ """
+ text_width = self.width - self.current_indent
indent = " "*self.current_indent
- return textwrap.fill(description,
- desc_width,
+ return textwrap.fill(text,
+ text_width,
initial_indent=indent,
- subsequent_indent=indent) + "\n"
+ subsequent_indent=indent)
+
+ def format_description(self, description):
+ if description:
+ return self._format_text(description) + "\n"
+ else:
+ return ""
+
+ def format_epilog(self, epilog):
+ if epilog:
+ return "\n" + self._format_text(epilog) + "\n"
+ else:
+ return ""
+
def expand_default(self, option):
if self.parser is None or not self.default_tag:
@@ -328,7 +365,7 @@
self, indent_increment, max_help_position, width, short_first)
def format_usage(self, usage):
- return _("usage: %s\n") % usage
+ return _("Usage: %s\n") % usage
def format_heading(self, heading):
return "%*s%s:\n" % (self.current_indent, "", heading)
@@ -353,8 +390,27 @@
return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))
-_builtin_cvt = { "int" : (int, _("integer")),
- "long" : (long, _("long integer")),
+def _parse_num(val, type):
+ if val[:2].lower() == "0x": # hexadecimal
+ radix = 16
+ elif val[:2].lower() == "0b": # binary
+ radix = 2
+ val = val[2:] or "0" # have to remove "0b" prefix
+ elif val[:1] == "0": # octal
+ radix = 8
+ else: # decimal
+ radix = 10
+
+ return type(val, radix)
+
+def _parse_int(val):
+ return _parse_num(val, int)
+
+def _parse_long(val):
+ return _parse_num(val, long)
+
+_builtin_cvt = { "int" : (_parse_int, _("integer")),
+ "long" : (_parse_long, _("long integer")),
"float" : (float, _("floating-point")),
"complex" : (complex, _("complex")) }
@@ -422,6 +478,7 @@
"store_true",
"store_false",
"append",
+ "append_const",
"count",
"callback",
"help",
@@ -435,6 +492,7 @@
"store_true",
"store_false",
"append",
+ "append_const",
"count")
# The set of actions for which it makes sense to supply a value
@@ -448,6 +506,10 @@
ALWAYS_TYPED_ACTIONS = ("store",
"append")
+ # The set of actions which take a 'const' attribute.
+ CONST_ACTIONS = ("store_const",
+ "append_const")
+
# The set of known types for option parsers. Again, listed here for
# constructor argument validation.
TYPES = ("string", "int", "long", "float", "complex", "choice")
@@ -572,9 +634,17 @@
# 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:
+ # Allow type objects or builtin type conversion functions
+ # (int, str, etc.) as an alternative to their names. (The
+ # complicated check of __builtin__ is only necessary for
+ # Python 2.1 and earlier, and is short-circuited by the
+ # first check on modern Pythons.)
+ import __builtin__
+ if ( type(self.type) is types.TypeType or
+ (hasattr(self.type, "__name__") and
+ getattr(__builtin__, self.type.__name__, None) is self.type) ):
self.type = self.type.__name__
+
if self.type == "str":
self.type = "string"
@@ -589,7 +659,7 @@
if self.choices is None:
raise OptionError(
"must supply a list of choices for type 'choice'", self)
- elif type(self.choices) not in (tuple, list):
+ elif type(self.choices) not in (types.TupleType, types.ListType):
raise OptionError(
"choices must be a list of strings ('%s' supplied)"
% str(type(self.choices)).split("'")[1], self)
@@ -613,7 +683,7 @@
self.dest = self._short_opts[0][1]
def _check_const(self):
- if self.action != "store_const" and self.const is not None:
+ if self.action not in self.CONST_ACTIONS and self.const is not None:
raise OptionError(
"'const' must not be supplied for action %r" % self.action,
self)
@@ -633,12 +703,12 @@
raise OptionError(
"callback not callable: %r" % self.callback, self)
if (self.callback_args is not None and
- type(self.callback_args) is not tuple):
+ type(self.callback_args) is not types.TupleType):
raise OptionError(
"callback_args, if supplied, must be a tuple: not %r"
% self.callback_args, self)
if (self.callback_kwargs is not None and
- type(self.callback_kwargs) is not dict):
+ type(self.callback_kwargs) is not types.DictType):
raise OptionError(
"callback_kwargs, if supplied, must be a dict: not %r"
% self.callback_kwargs, self)
@@ -720,6 +790,8 @@
setattr(values, dest, False)
elif action == "append":
values.ensure_value(dest, []).append(value)
+ elif action == "append_const":
+ values.ensure_value(dest, []).append(self.const)
elif action == "count":
setattr(values, dest, values.ensure_value(dest, 0) + 1)
elif action == "callback":
@@ -748,11 +820,9 @@
True, False
except NameError:
(True, False) = (1, 0)
-try:
- basestring
-except NameError:
- basestring = (str, unicode)
+def isbasestring(x):
+ return isinstance(x, types.StringType) or isinstance(x, types.UnicodeType)
class Values:
@@ -766,16 +836,13 @@
__repr__ = _repr
- def __eq__(self, other):
+ def __cmp__(self, other):
if isinstance(other, Values):
- return self.__dict__ == other.__dict__
- elif isinstance(other, dict):
- return self.__dict__ == other
+ return cmp(self.__dict__, other.__dict__)
+ elif isinstance(other, types.DictType):
+ return cmp(self.__dict__, other)
else:
- return False
-
- def __ne__(self, other):
- return not (self == other)
+ return -1
def _update_careful(self, dict):
"""
@@ -893,6 +960,13 @@
return self.description
+ def destroy(self):
+ """see OptionParser.destroy()."""
+ del self._short_opt
+ del self._long_opt
+ del self.defaults
+
+
# -- Option-adding methods -----------------------------------------
def _check_conflict(self, option):
@@ -926,7 +1000,7 @@
"""add_option(Option)
add_option(opt_str, ..., kwarg=val, ...)
"""
- if type(args[0]) is str:
+ if type(args[0]) is types.StringType:
option = self.option_class(*args, **kwargs)
elif len(args) == 1 and not kwargs:
option = args[0]
@@ -1018,6 +1092,11 @@
def set_title(self, title):
self.title = title
+ def destroy(self):
+ """see OptionParser.destroy()."""
+ OptionContainer.destroy(self)
+ del self.option_list
+
# -- Help-formatting methods ---------------------------------------
def format_help(self, formatter):
@@ -1044,6 +1123,8 @@
prog : string
the name of the current program (to override
os.path.basename(sys.argv[0])).
+ epilog : string
+ paragraph of help text to print after option help
option_groups : [OptionGroup]
list of option groups in this parser (option groups are
@@ -1102,7 +1183,8 @@
description=None,
formatter=None,
add_help_option=True,
- prog=None):
+ prog=None,
+ epilog=None):
OptionContainer.__init__(
self, option_class, conflict_handler, description)
self.set_usage(usage)
@@ -1114,6 +1196,7 @@
formatter = IndentedHelpFormatter()
self.formatter = formatter
self.formatter.set_parser(self)
+ self.epilog = epilog
# Populate the option list; initial sources are the
# standard_option_list class attribute, the 'option_list'
@@ -1124,6 +1207,22 @@
self._init_parsing_state()
+
+ def destroy(self):
+ """
+ Declare that you are done with this OptionParser. This cleans up
+ reference cycles so the OptionParser (and all objects referenced by
+ it) can be garbage-collected promptly. After calling destroy(), the
+ OptionParser is unusable.
+ """
+ OptionContainer.destroy(self)
+ for group in self.option_groups:
+ group.destroy()
+ del self.option_list
+ del self.option_groups
+ del self.formatter
+
+
# -- Private methods -----------------------------------------------
# (used by our or OptionContainer's constructor)
@@ -1167,7 +1266,7 @@
elif usage is SUPPRESS_USAGE:
self.usage = None
# For backwards compatibility with Optik 1.3 and earlier.
- elif usage.startswith("usage:" + " "):
+ elif usage.lower().startswith("usage: "):
self.usage = usage[7:]
else:
self.usage = usage
@@ -1201,7 +1300,7 @@
defaults = self.defaults.copy()
for option in self._get_all_options():
default = defaults.get(option.dest)
- if isinstance(default, basestring):
+ if isbasestring(default):
opt_str = option.get_opt_string()
defaults[option.dest] = option.check_value(opt_str, default)
@@ -1212,7 +1311,7 @@
def add_option_group(self, *args, **kwargs):
# XXX lots of overlap with OptionContainer.add_option()
- if type(args[0]) is str:
+ if type(args[0]) is types.StringType:
group = OptionGroup(self, *args, **kwargs)
elif len(args) == 1 and not kwargs:
group = args[0]
@@ -1276,7 +1375,7 @@
try:
stop = self._process_args(largs, rargs, values)
except (BadOptionError, OptionValueError), err:
- self.error(err.msg)
+ self.error(str(err))
args = largs + rargs
return self.check_values(values, args)
@@ -1401,7 +1500,7 @@
i += 1 # we have consumed a character
if not option:
- self.error(_("no such option: %s") % opt)
+ raise BadOptionError(opt)
if option.takes_value():
# Any characters left in arg? Pretend they're the
# next arg, and stop consuming characters of arg.
@@ -1501,7 +1600,7 @@
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))
@@ -1513,6 +1612,9 @@
# Drop the last "\n", or the header if no options or option groups:
return "".join(result[:-1])
+ def format_epilog(self, formatter):
+ return formatter.format_epilog(self.epilog)
+
def format_help(self, formatter=None):
if formatter is None:
formatter = self.formatter
@@ -1522,6 +1624,7 @@
if self.description:
result.append(self.format_description(formatter) + "\n")
result.append(self.format_option_help(formatter))
+ result.append(self.format_epilog(formatter))
return "".join(result)
def print_help(self, file=None):
@@ -1555,11 +1658,10 @@
if len(possibilities) == 1:
return possibilities[0]
elif not possibilities:
- raise BadOptionError(_("no such option: %s") % s)
+ raise BadOptionError(s)
else:
# More than one possible completion: ambiguous prefix.
- raise BadOptionError(_("ambiguous option: %s (%s?)")
- % (s, ", ".join(possibilities)))
+ raise AmbiguousOptionError(s, possibilities)
# Some day, there might be many Option classes. As of Optik 1.3, the
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py
index f656b9f..991c06d 100644
--- a/Lib/test/test_optparse.py
+++ b/Lib/test/test_optparse.py
@@ -10,17 +10,22 @@
import sys
import os
+import re
import copy
+import types
import unittest
from cStringIO import StringIO
from pprint import pprint
from test import test_support
+
from optparse import make_option, Option, IndentedHelpFormatter, \
TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
- BadOptionError, OptionValueError, Values, _match_abbrev
+ BadOptionError, OptionValueError, Values
+from optparse import _match_abbrev
+from optparse import _parse_num
# Do the right thing with boolean values for all known Python versions.
try:
@@ -28,6 +33,7 @@
except NameError:
(True, False) = (1, 0)
+retype = type(re.compile(''))
class InterceptedError(Exception):
def __init__(self,
@@ -96,7 +102,8 @@
args -- positional arguments to `func`
kwargs -- keyword arguments to `func`
expected_exception -- exception that should be raised
- expected_output -- output we expect to see
+ expected_message -- expected exception message (or pattern
+ if a compiled regex object)
Returns the exception raised for further testing.
"""
@@ -109,14 +116,23 @@
func(*args, **kwargs)
except expected_exception, err:
actual_message = str(err)
- self.assertEqual(actual_message,
- expected_message,
+ if isinstance(expected_message, retype):
+ self.assert_(expected_message.search(actual_message),
"""\
-expected exception message:
-'''%(expected_message)s'''
+expected exception message pattern:
+/%s/
actual exception message:
-'''%(actual_message)s'''
-""" % locals())
+'''%s'''
+""" % (expected_message.pattern, actual_message))
+ else:
+ self.assertEqual(actual_message,
+ expected_message,
+ """\
+expected exception message:
+'''%s'''
+actual exception message:
+'''%s'''
+""" % (expected_message, actual_message))
return err
else:
@@ -157,7 +173,9 @@
sys.stdout = save_stdout
except InterceptedError, err:
- self.assertEqual(output, expected_output)
+ if output != expected_output:
+ self.fail("expected: \n'''\n" + expected_output +
+ "'''\nbut got \n'''\n" + output + "'''")
self.assertEqual(err.exit_status, expected_status)
self.assertEqual(err.exit_message, expected_error)
else:
@@ -366,6 +384,23 @@
self.assertRaises(self.parser.remove_option, ('foo',), None,
ValueError, "no such option 'foo'")
+ def test_refleak(self):
+ # If an OptionParser is carrying around a reference to a large
+ # object, various cycles can prevent it from being GC'd in
+ # a timely fashion. destroy() breaks the cycles to ensure stuff
+ # can be cleaned up.
+ big_thing = [42]
+ refcount = sys.getrefcount(big_thing)
+ parser = OptionParser()
+ parser.add_option("-a", "--aaarggh")
+ parser.big_thing = big_thing
+
+ parser.destroy()
+ #self.assertEqual(refcount, sys.getrefcount(big_thing))
+ del parser
+ self.assertEqual(refcount, sys.getrefcount(big_thing))
+
+
class TestOptionValues(BaseTest):
def setUp(self):
pass
@@ -391,13 +426,21 @@
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")
+ def test_str_aliases_string(self):
+ self.parser.add_option("-s", type="str")
self.assertEquals(self.parser.get_option("-s").type, "string")
- self.assertEquals(self.parser.get_option("-t").type, "string")
+
+ def test_new_type_object(self):
+ self.parser.add_option("-s", type=str)
+ self.assertEquals(self.parser.get_option("-s").type, "string")
+ self.parser.add_option("-x", type=int)
+ self.assertEquals(self.parser.get_option("-x").type, "int")
+
+ def test_old_type_object(self):
+ self.parser.add_option("-s", type=types.StringType)
+ self.assertEquals(self.parser.get_option("-s").type, "string")
+ self.parser.add_option("-x", type=types.IntType)
+ self.assertEquals(self.parser.get_option("-x").type, "int")
# Custom type for testing processing of default values.
@@ -487,13 +530,13 @@
save_argv = sys.argv[:]
try:
sys.argv[0] = os.path.join("foo", "bar", "baz.py")
- parser = OptionParser("usage: %prog ...", version="%prog 1.2")
- expected_usage = "usage: baz.py ...\n"
+ parser = OptionParser("%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"
+ "Options:\n"
" --version show program's version number and exit\n"
" -h, --help show this help message and exit\n")
finally:
@@ -505,7 +548,7 @@
usage="%prog arg arg")
parser.remove_option("-h")
parser.remove_option("--version")
- expected_usage = "usage: thingy arg arg\n"
+ expected_usage = "Usage: thingy arg arg\n"
self.assertUsage(parser, expected_usage)
self.assertVersion(parser, "thingy 0.1")
self.assertHelp(parser, expected_usage + "\n")
@@ -515,9 +558,9 @@
def setUp(self):
self.parser = OptionParser(prog="test")
self.help_prefix = """\
-usage: test [options]
+Usage: test [options]
-options:
+Options:
-h, --help show this help message and exit
"""
self.file_help = "read from FILE [default: %default]"
@@ -699,13 +742,16 @@
self.assertParseOK(["-a", "--", "foo", "bar"],
{'a': "--", 'boo': None, 'foo': None},
["foo", "bar"]),
+ self.assertParseOK(["-a", "--", "--foo", "bar"],
+ {'a': "--", 'boo': None, 'foo': ["bar"]},
+ []),
def test_short_option_joined_and_separator(self):
self.assertParseOK(["-ab", "--", "--foo", "bar"],
{'a': "b", 'boo': None, 'foo': None},
["--foo", "bar"]),
- def test_invalid_option_becomes_positional_arg(self):
+ def test_hyphen_becomes_positional_arg(self):
self.assertParseOK(["-ab", "-", "--foo", "bar"],
{'a': "b", 'boo': None, 'foo': ["bar"]},
["-"])
@@ -870,6 +916,8 @@
type="float", dest="point")
self.parser.add_option("-f", "--foo", action="append", nargs=2,
type="int", dest="foo")
+ self.parser.add_option("-z", "--zero", action="append_const",
+ dest="foo", const=(0, 0))
def test_nargs_append(self):
self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],
@@ -885,6 +933,11 @@
{'point': None, 'foo':[(3, 4)]},
[])
+ def test_nargs_append_const(self):
+ self.assertParseOK(["--zero", "--foo", "3", "4", "-z"],
+ {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]},
+ [])
+
class TestVersion(BaseTest):
def test_version(self):
self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
@@ -960,8 +1013,14 @@
self.parser.add_option("-a", None, type="string", dest="a")
self.parser.add_option("-f", "--file", type="file", dest="file")
+ def tearDown(self):
+ if os.path.isdir(test_support.TESTFN):
+ os.rmdir(test_support.TESTFN)
+ elif os.path.isfile(test_support.TESTFN):
+ os.unlink(test_support.TESTFN)
+
class MyOption (Option):
- def check_file (option, opt, value):
+ def check_file(option, opt, value):
if not os.path.exists(value):
raise OptionValueError("%s: file does not exist" % value)
elif not os.path.isfile(value):
@@ -972,25 +1031,23 @@
TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
TYPE_CHECKER["file"] = check_file
- def test_extend_file(self):
+ def test_filetype_ok(self):
open(test_support.TESTFN, "w").close()
self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
{'file': test_support.TESTFN, 'a': 'foo'},
[])
- os.unlink(test_support.TESTFN)
-
- def test_extend_file_nonexistent(self):
+ def test_filetype_noexist(self):
self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
"%s: file does not exist" %
test_support.TESTFN)
- def test_file_irregular(self):
+ def test_filetype_notfile(self):
os.mkdir(test_support.TESTFN)
self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
"%s: not a regular file" %
test_support.TESTFN)
- os.rmdir(test_support.TESTFN)
+
class TestExtendAddActions(BaseTest):
def setUp(self):
@@ -1003,7 +1060,7 @@
STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
- def take_action (self, action, dest, opt, value, values, parser):
+ def take_action(self, action, dest, opt, value, values, parser):
if action == "extend":
lvalue = value.split(",")
values.ensure_value(dest, []).extend(lvalue)
@@ -1072,7 +1129,7 @@
callback=lambda: None, type="string",
help="foo")
- expected_help = ("options:\n"
+ expected_help = ("Options:\n"
" -t TEST, --test=TEST foo\n")
self.assertHelp(parser, expected_help)
@@ -1085,7 +1142,7 @@
dest="points", default=[])]
self.parser = OptionParser(option_list=options)
- def process_tuple (self, option, opt, value, parser_, len, type):
+ def process_tuple(self, option, opt, value, parser_, len, type):
self.assertEqual(len, 3)
self.assert_(type is int)
@@ -1110,7 +1167,7 @@
self.parser = OptionParser(option_list=options)
# Callback that meddles in rargs, largs
- def process_n (self, option, opt, value, parser_):
+ def process_n(self, option, opt, value, parser_):
# option is -3, -5, etc.
nargs = int(opt[1:])
rargs = parser_.rargs
@@ -1139,7 +1196,7 @@
callback=self.process_many, type="int")]
self.parser = OptionParser(option_list=options)
- def process_many (self, option, opt, value, parser_):
+ def process_many(self, option, opt, value, parser_):
if opt == "-a":
self.assertEqual(value, ("foo", "bar"))
elif opt == "--apple":
@@ -1162,7 +1219,7 @@
self.parser.add_option("--foo-bar", action="callback",
callback=self.check_abbrev)
- def check_abbrev (self, option, opt, value, parser):
+ def check_abbrev(self, option, opt, value, parser):
self.assertEqual(opt, "--foo-bar")
def test_abbrev_callback_expansion(self):
@@ -1177,7 +1234,7 @@
self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
option_list=options)
- def variable_args (self, option, opt, value, parser):
+ def variable_args(self, option, opt, value, parser):
self.assert_(value is None)
done = 0
value = []
@@ -1229,7 +1286,7 @@
self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
option_list=options)
- def show_version (self, option, opt, value, parser):
+ def show_version(self, option, opt, value, parser):
parser.values.show_version = 1
class TestConflict(ConflictBase):
@@ -1280,7 +1337,7 @@
def test_conflict_resolve_help(self):
self.assertOutput(["-h"], """\
-options:
+Options:
--verbose increment verbosity
-h, --help show this help message and exit
-v, --version show version
@@ -1319,7 +1376,7 @@
def test_conflict_override_help(self):
self.assertOutput(["-h"], """\
-options:
+Options:
-h, --help show this help message and exit
-n, --dry-run dry run mode
""")
@@ -1332,9 +1389,9 @@
# -- Other testing. ----------------------------------------------------
_expected_help_basic = """\
-usage: bar.py [options]
+Usage: bar.py [options]
-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)
@@ -1343,9 +1400,9 @@
"""
_expected_help_long_opts_first = """\
-usage: bar.py [options]
+Usage: bar.py [options]
-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)
@@ -1358,7 +1415,7 @@
=====
bar.py [options]
-options
+Options
=======
-a APPLE throw APPLEs at basket
--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the
@@ -1368,9 +1425,9 @@
"""
_expected_help_short_lines = """\
-usage: bar.py [options]
+Usage: bar.py [options]
-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
@@ -1382,15 +1439,8 @@
class TestHelp(BaseTest):
def setUp(self):
- self.orig_columns = os.environ.get('COLUMNS')
self.parser = self.make_parser(80)
- def tearDown(self):
- if self.orig_columns is None:
- del os.environ['COLUMNS']
- else:
- os.environ['COLUMNS'] = self.orig_columns
-
def make_parser(self, columns):
options = [
make_option("-a", type="string", dest='a',
@@ -1419,7 +1469,7 @@
self.assertHelpEquals(_expected_help_basic)
def test_help_old_usage(self):
- self.parser.set_usage("usage: %prog [options]")
+ self.parser.set_usage("Usage: %prog [options]")
self.assertHelpEquals(_expected_help_basic)
def test_help_long_opts_first(self):
@@ -1449,13 +1499,13 @@
group.add_option("-g", action="store_true", help="Group option.")
self.parser.add_option_group(group)
- self.assertHelpEquals("""\
-usage: bar.py [options]
+ expect = """\
+Usage: bar.py [options]
This is the program description for bar.py. bar.py has an option group as
well as single options.
-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)
@@ -1467,9 +1517,12 @@
that some of them bite.
-g Group option.
-""")
+"""
+ self.assertHelpEquals(expect)
+ self.parser.epilog = "Please report bugs to /dev/null."
+ self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n")
class TestMatchAbbrev(BaseTest):
@@ -1490,6 +1543,43 @@
BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
+class TestParseNumber(BaseTest):
+ def setUp(self):
+ self.parser = InterceptingOptionParser()
+ self.parser.add_option("-n", type=int)
+ self.parser.add_option("-l", type=long)
+
+ def test_parse_num_fail(self):
+ self.assertRaises(
+ _parse_num, ("", int), {},
+ ValueError,
+ re.compile(r"invalid literal for int().*: '?'?"))
+ self.assertRaises(
+ _parse_num, ("0xOoops", long), {},
+ ValueError,
+ re.compile(r"invalid literal for long().*: '?0xOoops'?"))
+
+ def test_parse_num_ok(self):
+ self.assertEqual(_parse_num("0", int), 0)
+ self.assertEqual(_parse_num("0x10", int), 16)
+ self.assertEqual(_parse_num("0XA", long), 10L)
+ self.assertEqual(_parse_num("010", long), 8L)
+ self.assertEqual(_parse_num("0b11", int), 3)
+ self.assertEqual(_parse_num("0b", long), 0L)
+
+ def test_numeric_options(self):
+ self.assertParseOK(["-n", "42", "-l", "0x20"],
+ { "n": 42, "l": 0x20 }, [])
+ self.assertParseOK(["-n", "0b0101", "-l010"],
+ { "n": 5, "l": 8 }, [])
+ self.assertParseFail(["-n008"],
+ "option -n: invalid integer value: '008'")
+ self.assertParseFail(["-l0b0123"],
+ "option -l: invalid long integer value: '0b0123'")
+ self.assertParseFail(["-l", "0x12x"],
+ "option -l: invalid long integer value: '0x12x'")
+
+
def _testclasses():
mod = sys.modules[__name__]
return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]