summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_optparse.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_optparse.py')
-rw-r--r--Lib/test/test_optparse.py406
1 files changed, 214 insertions, 192 deletions
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py
index 883194e..c02dd10 100644
--- a/Lib/test/test_optparse.py
+++ b/Lib/test/test_optparse.py
@@ -17,10 +17,37 @@ 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, _match_abbrev)
+from optparse import make_option, Option, IndentedHelpFormatter, \
+ TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
+ SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
+ BadOptionError, OptionValueError, Values, _match_abbrev
+
+# Do the right thing with boolean values for all known Python versions.
+try:
+ True, False
+except NameError:
+ (True, False) = (1, 0)
+
+
+class InterceptedError(Exception):
+ def __init__(self,
+ error_message=None,
+ exit_status=None,
+ exit_message=None):
+ self.error_message = error_message
+ self.exit_status = exit_status
+ self.exit_message = exit_message
+
+ def __str__(self):
+ return self.error_message or self.exit_message or "intercepted error"
+
+class InterceptingOptionParser(OptionParser):
+ def exit(self, status=0, msg=None):
+ raise InterceptedError(exit_status=status, exit_message=msg)
+
+ def error(self, msg):
+ raise InterceptedError(error_message=msg)
+
class BaseTest(unittest.TestCase):
def assertParseOK(self, args, expected_opts, expected_positional_args):
@@ -58,12 +85,11 @@ Args were %(args)s.""" % locals ())
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.
+ expected_message):
+ """
+ Assert that the expected exception is raised when calling a
+ function, and that the right error message is included with
+ that exception.
Arguments:
func -- the function to call
@@ -71,9 +97,6 @@ Args were %(args)s.""" % locals ())
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.
"""
@@ -81,25 +104,18 @@ Args were %(args)s.""" % locals ())
args = ()
if kwargs is None:
kwargs = {}
- if get_output is None:
- get_output = self.exception
try:
- out = func(*args, **kwargs)
+ func(*args, **kwargs)
except expected_exception, err:
- 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'''
+ actual_message = str(err)
+ self.assertEqual(actual_message,
+ expected_message,
+ """\
+expected exception message:
+'''%(expected_message)s'''
+actual exception message:
+'''%(actual_message)s'''
""" % locals())
return err
@@ -110,44 +126,46 @@ with args %(args)r
and kwargs %(kwargs)r
""" % locals ())
- # -- Functions to be used as the get_output argument to assertRaises ------
-
- def exception(self, err):
- return str(err)
-
- 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."""
- save_stderr = sys.stderr
+ """
+ Assert the parser fails with the expected message. Caller
+ must ensure that self.parser is an InterceptingOptionParser.
+ """
try:
- sys.stderr = StringIO()
- self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
- SystemExit, expected_output,
- self.redirected_stderr)
- finally:
- sys.stderr = save_stderr
+ self.parser.parse_args(cmdline_args)
+ except InterceptedError, err:
+ self.assertEqual(err.error_message, expected_output)
+ else:
+ self.assertFalse("expected parse failure")
- def assertStdoutEquals(self, cmdline_args, expected_output):
+ def assertOutput(self,
+ cmdline_args,
+ expected_output,
+ expected_status=0,
+ expected_error=None):
"""Assert the parser prints the expected output on stdout."""
save_stdout = sys.stdout
try:
- sys.stdout = StringIO()
- self.assertRaises(self.parser.parse_args, (cmdline_args,), None,
- SystemExit, expected_output,
- self.redirected_stdout)
- finally:
- sys.stdout = save_stdout
+ try:
+ sys.stdout = StringIO()
+ self.parser.parse_args(cmdline_args)
+ finally:
+ output = sys.stdout.getvalue()
+ sys.stdout = save_stdout
+
+ except InterceptedError, err:
+ self.assertEqual(output, expected_output)
+ self.assertEqual(err.exit_status, expected_status)
+ self.assertEqual(err.exit_message, expected_error)
+ else:
+ self.assertFalse("expected parser.exit()")
- def assertTypeError(self, func, expected_output, *args):
- """Assert a TypeError is raised when executing func."""
- self.assertRaises(func, args, None, TypeError, expected_output)
+ def assertTypeError(self, func, expected_message, *args):
+ """Assert that TypeError is raised when executing func."""
+ self.assertRaises(func, args, None, TypeError, expected_message)
def assertHelp(self, parser, expected_help):
actual_help = parser.format_help()
@@ -159,120 +177,133 @@ and kwargs %(kwargs)r
# -- Test make_option() aka Option -------------------------------------
-# It's not necessary to test correct options here. All the tests in the
+# It's not necessary to test correct options here. All the tests in the
# parser.parse_args() section deal with those, because they're needed
-# there. Duplication makes no sense to me.
+# there.
class TestOptionChecks(BaseTest):
def setUp(self):
self.parser = OptionParser(usage=SUPPRESS_USAGE)
- def assertOptionError(self, expected_output, args=[], kwargs={}):
+ def assertOptionError(self, expected_message, args=[], kwargs={}):
self.assertRaises(make_option, args, kwargs,
- OptionError, expected_output)
+ OptionError, expected_message)
def test_opt_string_empty(self):
self.assertTypeError(make_option,
"at least one option string must be supplied")
def test_opt_string_too_short(self):
- self.assertOptionError("invalid option string 'b': "
- "must be at least two characters long",
- ["b"])
+ self.assertOptionError(
+ "invalid option string 'b': must be at least two characters long",
+ ["b"])
def test_opt_string_short_invalid(self):
- self.assertOptionError("invalid short option string '--': must be "
- "of the form -x, (x any non-dash char)",
- ["--"])
+ self.assertOptionError(
+ "invalid short option string '--': must be "
+ "of the form -x, (x any non-dash char)",
+ ["--"])
def test_opt_string_long_invalid(self):
- self.assertOptionError("invalid long option string '---': "
- "must start with --, followed by non-dash",
- ["---"])
+ self.assertOptionError(
+ "invalid long option string '---': "
+ "must start with --, followed by non-dash",
+ ["---"])
def test_attr_invalid(self):
- self.assertOptionError("invalid keyword arguments: foo, bar",
- ["-b"], {'foo': None, 'bar': None})
+ self.assertOptionError(
+ "option -b: invalid keyword arguments: foo, bar",
+ ["-b"], {'foo': None, 'bar': None})
def test_action_invalid(self):
- self.assertOptionError("invalid action: 'foo'",
- ["-b"], {'action': 'foo'})
+ self.assertOptionError(
+ "option -b: invalid action: 'foo'",
+ ["-b"], {'action': 'foo'})
def test_type_invalid(self):
- self.assertOptionError("invalid option type: 'foo'",
- ["-b"], {'type': 'foo'})
- self.assertOptionError("invalid option type: 'tuple'",
- ["-b"], {'type': tuple})
+ self.assertOptionError(
+ "option -b: invalid option type: 'foo'",
+ ["-b"], {'type': 'foo'})
+ self.assertOptionError(
+ "option -b: invalid option type: 'tuple'",
+ ["-b"], {'type': tuple})
def test_no_type_for_action(self):
- self.assertOptionError("must not supply a type for action 'count'",
- ["-b"], {'action': 'count', 'type': 'int'})
+ self.assertOptionError(
+ "option -b: must not supply a type for action 'count'",
+ ["-b"], {'action': 'count', 'type': 'int'})
def test_no_choices_list(self):
- self.assertOptionError("must supply a list of "
- "choices for type 'choice'",
- ["-b", "--bad"], {'type': "choice"})
+ self.assertOptionError(
+ "option -b/--bad: must supply a list of "
+ "choices for type 'choice'",
+ ["-b", "--bad"], {'type': "choice"})
def test_bad_choices_list(self):
typename = type('').__name__
- self.assertOptionError("choices must be a list of "
- "strings ('%s' supplied)" % typename,
- ["-b", "--bad"],
- {'type': "choice", 'choices':"bad choices"})
+ self.assertOptionError(
+ "option -b/--bad: choices must be a list of "
+ "strings ('%s' supplied)" % typename,
+ ["-b", "--bad"],
+ {'type': "choice", 'choices':"bad choices"})
def test_no_choices_for_type(self):
- self.assertOptionError("must not supply choices for type 'int'",
- ["-b"], {'type': 'int', 'choices':"bad"})
+ self.assertOptionError(
+ "option -b: must not supply choices for type 'int'",
+ ["-b"], {'type': 'int', 'choices':"bad"})
def test_no_const_for_action(self):
- self.assertOptionError("'const' must not be supplied for action "
- "'store'",
- ["-b"], {'action': 'store', 'const': 1})
+ self.assertOptionError(
+ "option -b: 'const' must not be supplied for action 'store'",
+ ["-b"], {'action': 'store', 'const': 1})
def test_no_nargs_for_action(self):
- self.assertOptionError("'nargs' must not be supplied for action "
- "'count'",
- ["-b"], {'action': 'count', 'nargs': 2})
+ self.assertOptionError(
+ "option -b: 'nargs' must not be supplied for action 'count'",
+ ["-b"], {'action': 'count', 'nargs': 2})
def test_callback_not_callable(self):
- self.assertOptionError("callback not callable: 'foo'",
- ["-b"], {'action': 'callback',
- 'callback': 'foo'})
+ self.assertOptionError(
+ "option -b: callback not callable: 'foo'",
+ ["-b"], {'action': 'callback',
+ 'callback': 'foo'})
def dummy(self):
pass
def test_callback_args_no_tuple(self):
- self.assertOptionError("callback_args, if supplied, must be a tuple: "
- "not 'foo'",
- ["-b"], {'action': 'callback',
- 'callback': self.dummy,
- 'callback_args': 'foo'})
+ self.assertOptionError(
+ "option -b: callback_args, if supplied, "
+ "must be a tuple: not 'foo'",
+ ["-b"], {'action': 'callback',
+ 'callback': self.dummy,
+ 'callback_args': 'foo'})
def test_callback_kwargs_no_dict(self):
- self.assertOptionError("callback_kwargs, if supplied, must be a dict: "
- "not 'foo'",
- ["-b"], {'action': 'callback',
- 'callback': self.dummy,
- 'callback_kwargs': 'foo'})
+ self.assertOptionError(
+ "option -b: callback_kwargs, if supplied, "
+ "must be a dict: not 'foo'",
+ ["-b"], {'action': 'callback',
+ 'callback': self.dummy,
+ 'callback_kwargs': 'foo'})
def test_no_callback_for_action(self):
- self.assertOptionError("callback supplied ('foo') for "
- "non-callback option",
- ["-b"], {'action': 'store',
- 'callback': 'foo'})
+ self.assertOptionError(
+ "option -b: callback supplied ('foo') for non-callback option",
+ ["-b"], {'action': 'store',
+ 'callback': 'foo'})
def test_no_callback_args_for_action(self):
- self.assertOptionError("callback_args supplied for non-callback "
- "option",
- ["-b"], {'action': 'store',
- 'callback_args': 'foo'})
+ self.assertOptionError(
+ "option -b: callback_args supplied for non-callback option",
+ ["-b"], {'action': 'store',
+ 'callback_args': 'foo'})
def test_no_callback_kwargs_for_action(self):
- self.assertOptionError("callback_kwargs supplied for non-callback "
- "option",
- ["-b"], {'action': 'store',
- 'callback_kwargs': 'foo'})
+ self.assertOptionError(
+ "option -b: callback_kwargs supplied for non-callback option",
+ ["-b"], {'action': 'store',
+ 'callback_kwargs': 'foo'})
class TestOptionParser(BaseTest):
def setUp(self):
@@ -335,6 +366,27 @@ class TestOptionParser(BaseTest):
self.assertRaises(self.parser.remove_option, ('foo',), None,
ValueError, "no such option 'foo'")
+class TestOptionValues(BaseTest):
+ def setUp(self):
+ pass
+
+ def test_basics(self):
+ values = Values()
+ self.assertEqual(vars(values), {})
+ self.assertEqual(values, {})
+ self.assertNotEqual(values, {"foo": "bar"})
+ self.assertNotEqual(values, "")
+
+ dict = {"foo": "bar", "baz": 42}
+ values = Values(defaults=dict)
+ self.assertEqual(vars(values), dict)
+ self.assertEqual(values, dict)
+ self.assertNotEqual(values, {"foo": "bar"})
+ self.assertNotEqual(values, {})
+ self.assertNotEqual(values, "")
+ self.assertNotEqual(values, [])
+
+
class TestTypeAliases(BaseTest):
def setUp(self):
self.parser = OptionParser()
@@ -346,7 +398,7 @@ class TestTypeAliases(BaseTest):
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 }
@@ -434,17 +486,16 @@ class TestProgName(BaseTest):
# Make sure that program name taken from sys.argv[0] by default.
save_argv = sys.argv[:]
try:
- # XXX Should the path be hard-coding forward-slashes?
- sys.argv[0] = "/foo/bar/baz.py"
+ sys.argv[0] = os.path.join("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")
+ expected_usage + "\n" +
+ "options:\n"
+ " --version show program's version number and exit\n"
+ " -h, --help show this help message and exit\n")
finally:
sys.argv[:] = save_argv
@@ -503,7 +554,7 @@ options:
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)
@@ -544,7 +595,8 @@ class TestStandard(BaseTest):
make_option("-b", "--boo", type="int", dest='boo'),
make_option("--foo", action="append")]
- self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
+ option_list=options)
def test_required_value(self):
self.assertParseFail(["-a"], "-a option requires an argument")
@@ -707,7 +759,7 @@ class TestBool(BaseTest):
class TestChoice(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.parser.add_option("-c", action="store", type="choice",
dest="choice", choices=["one", "two", "three"])
@@ -730,7 +782,7 @@ class TestChoice(BaseTest):
class TestCount(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.v_opt = make_option("-v", action="count", dest="verbose")
self.parser.add_option(self.v_opt)
self.parser.add_option("--verbose", type="int", dest="verbose")
@@ -786,9 +838,9 @@ class TestCount(BaseTest):
self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
{'verbose': 1}, [])
-class TestNArgs(BaseTest):
+class TestMultipleArgs(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.parser.add_option("-p", "--point",
action="store", nargs=3, type="float", dest="point")
@@ -811,9 +863,9 @@ class TestNArgs(BaseTest):
self.assertParseFail(["--point", "1.0", "3.5"],
"--point option requires 3 arguments")
-class TestNArgsAppend(BaseTest):
+class TestMultipleArgsAppend(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.parser.add_option("-p", "--point", action="store", nargs=3,
type="float", dest="point")
self.parser.add_option("-f", "--foo", action="append", nargs=2,
@@ -835,14 +887,17 @@ class TestNArgsAppend(BaseTest):
class TestVersion(BaseTest):
def test_version(self):
- oldargv = sys.argv[0]
- sys.argv[0] = "./foo/bar"
- self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1")
- self.assertStdoutEquals(["--version"], "bar 0.1\n")
- sys.argv[0] = oldargv
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
+ version="%prog 0.1")
+ save_argv = sys.argv[:]
+ try:
+ sys.argv[0] = os.path.join(os.curdir, "foo", "bar")
+ self.assertOutput(["--version"], "bar 0.1\n")
+ finally:
+ sys.argv[:] = save_argv
def test_no_version(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.assertParseFail(["--version"],
"no such option: --version")
@@ -900,8 +955,8 @@ class TestOptionGroup(BaseTest):
class TestExtendAddTypes(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE,
- option_class=self.MyOption)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
+ option_class=self.MyOption)
self.parser.add_option("-a", None, type="string", dest="a")
self.parser.add_option("-f", "--file", type="file", dest="file")
@@ -1119,7 +1174,8 @@ class TestCallbackVarArgs(BaseTest):
make_option("-b", action="store_true", dest="b"),
make_option("-c", "--callback", action="callback",
callback=self.variable_args, dest="c")]
- self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
+ option_list=options)
def variable_args (self, option, opt, value, parser):
self.assert_(value is None)
@@ -1170,7 +1226,8 @@ class ConflictBase(BaseTest):
def setUp(self):
options = [make_option("-v", "--verbose", action="count",
dest="verbose", help="increment verbosity")]
- self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
+ option_list=options)
def show_version (self, option, opt, value, parser):
parser.values.show_version = 1
@@ -1201,41 +1258,6 @@ class TestConflict(ConflictBase):
ValueError, "invalid conflict_resolution value 'foo'")
-class TestConflictIgnore(ConflictBase):
- """Test the old (Optik <= 1.1 behaviour) -- arguably broken, but
- still available so should be tested.
- """
-
- def setUp(self):
- ConflictBase.setUp(self)
- self.parser.set_conflict_handler("ignore")
- self.parser.add_option("-v", "--version", action="callback",
- callback=self.show_version, help="show version")
-
- def test_conflict_ignore(self):
- v_opt = self.parser.get_option("-v")
- verbose_opt = self.parser.get_option("--verbose")
- version_opt = self.parser.get_option("--version")
-
- self.assert_(v_opt is version_opt)
- self.assert_(v_opt is not verbose_opt)
- self.assertEqual(v_opt._long_opts, ["--version"])
- self.assertEqual(version_opt._short_opts, ["-v"])
- self.assertEqual(verbose_opt._short_opts, ["-v"])
-
- def test_conflict_ignore_help(self):
- self.assertStdoutEquals(["-h"], """\
-options:
- -v, --verbose increment verbosity
- -h, --help show this help message and exit
- -v, --version show version
-""")
-
- def test_conflict_ignore_short_opt(self):
- self.assertParseOK(["-v"],
- {'show_version': 1, 'verbose': None},
- [])
-
class TestConflictResolve(ConflictBase):
def setUp(self):
ConflictBase.setUp(self)
@@ -1257,7 +1279,7 @@ class TestConflictResolve(ConflictBase):
self.assertEqual(verbose_opt._long_opts, ["--verbose"])
def test_conflict_resolve_help(self):
- self.assertStdoutEquals(["-h"], """\
+ self.assertOutput(["-h"], """\
options:
--verbose increment verbosity
-h, --help show this help message and exit
@@ -1281,7 +1303,7 @@ options:
class TestConflictOverride(BaseTest):
def setUp(self):
- self.parser = OptionParser(usage=SUPPRESS_USAGE)
+ self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
self.parser.set_conflict_handler("resolve")
self.parser.add_option("-n", "--dry-run",
action="store_true", dest="dry_run",
@@ -1296,7 +1318,7 @@ class TestConflictOverride(BaseTest):
self.assertEqual(opt._long_opts, ["--dry-run"])
def test_conflict_override_help(self):
- self.assertStdoutEquals(["-h"], """\
+ self.assertOutput(["-h"], """\
options:
-h, --help show this help message and exit
-n, --dry-run dry run mode
@@ -1375,16 +1397,16 @@ class TestHelp(BaseTest):
help="store FOO in the foo list for later fooing"),
]
os.environ['COLUMNS'] = str(columns)
- return OptionParser(option_list=options)
+ return InterceptingOptionParser(option_list=options)
def assertHelpEquals(self, expected_output):
- # This trick is used to make optparse believe bar.py is being executed.
- oldargv = sys.argv[0]
- sys.argv[0] = "./foo/bar.py"
-
- self.assertStdoutEquals(["-h"], expected_output)
-
- sys.argv[0] = oldargv
+ save_argv = sys.argv[:]
+ try:
+ # Make optparse believe bar.py is being executed.
+ sys.argv[0] = os.path.join("foo", "bar.py")
+ self.assertOutput(["-h"], expected_output)
+ finally:
+ sys.argv[:] = save_argv
def test_help(self):
self.assertHelpEquals(_expected_help_basic)
@@ -1441,7 +1463,7 @@ options:
""")
-
+
class TestMatchAbbrev(BaseTest):
def test_match_abbrev(self):