diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -15,25 +15,16 @@ from io import StringIO from test import support from unittest import mock class StdIOBuffer(StringIO): pass class TestCase(unittest.TestCase): - def assertEqual(self, obj1, obj2): - if obj1 != obj2: - print('') - print(repr(obj1)) - print(repr(obj2)) - print(obj1) - print(obj2) - super(TestCase, self).assertEqual(obj1, obj2) - def setUp(self): # The tests assume that line wrapping occurs at 80 columns, but this # behaviour can be overridden by setting the COLUMNS environment # variable. To ensure that this assumption is true, unset COLUMNS. env = support.EnvironmentVarGuard() env.unset("COLUMNS") self.addCleanup(env.__exit__) @@ -1988,24 +1979,19 @@ class TestAddSubparsers(TestCase): subcommands: command help {1,2} additional text ''')) def _test_subparser_help(self, args_str, expected_help): - try: + with self.assertRaises(ArgumentParserError) as cm: self.parser.parse_args(args_str.split()) - except ArgumentParserError: - err = sys.exc_info()[1] - if err.stdout != expected_help: - print(repr(expected_help)) - print(repr(err.stdout)) - self.assertEqual(err.stdout, expected_help) + self.assertEqual(expected_help, cm.exception.stdout) def test_subparser1_help(self): self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\ usage: PROG bar 1 [-h] [-w W] {a,b,c} 1 description positional arguments: @@ -2834,51 +2820,52 @@ class TestSetDefaults(TestCase): # ================= # Get default tests # ================= class TestGetDefault(TestCase): def test_get_default(self): parser = ErrorRaisingArgumentParser() - self.assertEqual(None, parser.get_default("foo")) - self.assertEqual(None, parser.get_default("bar")) + self.assertIsNone(parser.get_default("foo")) + self.assertIsNone(parser.get_default("bar")) parser.add_argument("--foo") - self.assertEqual(None, parser.get_default("foo")) - self.assertEqual(None, parser.get_default("bar")) + self.assertIsNone(parser.get_default("foo")) + self.assertIsNone(parser.get_default("bar")) parser.add_argument("--bar", type=int, default=42) - self.assertEqual(None, parser.get_default("foo")) + self.assertIsNone(parser.get_default("foo")) self.assertEqual(42, parser.get_default("bar")) parser.set_defaults(foo="badger") self.assertEqual("badger", parser.get_default("foo")) self.assertEqual(42, parser.get_default("bar")) # ========================== # Namespace 'contains' tests # ========================== class TestNamespaceContainsSimple(TestCase): def test_empty(self): ns = argparse.Namespace() self.assertEqual('' in ns, False) self.assertEqual('' not in ns, True) - self.assertEqual('x' in ns, False) + self.assertNotIn('x', ns) def test_non_empty(self): ns = argparse.Namespace(x=1, y=2) self.assertEqual('x' in ns, True) self.assertEqual('x' not in ns, False) - self.assertEqual('y' in ns, True) self.assertEqual('' in ns, False) - self.assertEqual('xx' in ns, False) - self.assertEqual('z' in ns, False) + self.assertIn('x', ns) + self.assertIn('y', ns) + self.assertNotIn('xx', ns) + self.assertNotIn('z', ns) # ===================== # Help formatting tests # ===================== class TestHelpFormattingMetaclass(type): def __init__(cls, name, bases, bodydict): @@ -2924,23 +2911,16 @@ class TestHelpFormattingMetaclass(type): for subparser_sig in subparsers_sigs: subparsers.add_parser(*subparser_sig.args, **subparser_sig.kwargs) return parser def _test(self, tester, parser_text): expected_text = getattr(tester, self.func_suffix) expected_text = textwrap.dedent(expected_text) - if expected_text != parser_text: - print(repr(expected_text)) - print(repr(parser_text)) - for char1, char2 in zip(expected_text, parser_text): - if char1 != char2: - print('first diff: %r %r' % (char1, char2)) - break tester.assertEqual(expected_text, parser_text) def test_format(self, tester): parser = self._get_parser(tester) format = getattr(parser, 'format_%s' % self.func_suffix) self._test(tester, format()) def test_print(self, tester): @@ -4211,34 +4191,25 @@ class TestInvalidArgumentConstructors(Te self.assertValueError('--foo', type='int') self.assertValueError('--foo', type=(int, float)) def test_invalid_action(self): self.assertValueError('-x', action='foo') self.assertValueError('foo', action='baz') self.assertValueError('--foo', action=('store', 'append')) parser = argparse.ArgumentParser() - try: + with self.assertRaisesRegex(ValueError, "unknown action"): parser.add_argument("--foo", action="store-true") - except ValueError: - e = sys.exc_info()[1] - expected = 'unknown action' - msg = 'expected %r, found %r' % (expected, e) - self.assertTrue(expected in str(e), msg) def test_multiple_dest(self): parser = argparse.ArgumentParser() parser.add_argument(dest='foo') - try: + expected_regex = 'dest supplied twice for positional argument' + with self.assertRaisesRegex(ValueError, expected_regex): parser.add_argument('bar', dest='baz') - except ValueError: - e = sys.exc_info()[1] - expected = 'dest supplied twice for positional argument' - msg = 'expected %r, found %r' % (expected, e) - self.assertTrue(expected in str(e), msg) def test_no_argument_actions(self): for action in ['store_const', 'store_true', 'store_false', 'append_const', 'count']: for attrs in [dict(type=int), dict(nargs='+'), dict(choices='ab')]: self.assertTypeError('-x', action=action, **attrs) @@ -4385,57 +4356,51 @@ class TestConflictHandling(TestCase): # ============================= # Help and Version option tests # ============================= class TestOptionalsHelpVersionActions(TestCase): """Test the help and version actions""" - def _get_error(self, func, *args, **kwargs): - try: - func(*args, **kwargs) - except ArgumentParserError: - return sys.exc_info()[1] - else: - self.assertRaises(ArgumentParserError, func, *args, **kwargs) - def assertPrintHelpExit(self, parser, args_str): - self.assertEqual( - parser.format_help(), - self._get_error(parser.parse_args, args_str.split()).stdout) + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(args_str.split()) + self.assertEqual(parser.format_help(), cm.exception.stdout) def assertArgumentParserError(self, parser, *args): self.assertRaises(ArgumentParserError, parser.parse_args, args) def test_version(self): parser = ErrorRaisingArgumentParser() parser.add_argument('-v', '--version', action='version', version='1.0') self.assertPrintHelpExit(parser, '-h') self.assertPrintHelpExit(parser, '--help') self.assertRaises(AttributeError, getattr, parser, 'format_version') def test_version_format(self): parser = ErrorRaisingArgumentParser(prog='PPP') parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5') - msg = self._get_error(parser.parse_args, ['-v']).stdout - self.assertEqual('PPP 3.5\n', msg) + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(['-v']) + self.assertEqual('PPP 3.5\n', cm.exception.stdout) def test_version_no_help(self): parser = ErrorRaisingArgumentParser(add_help=False) parser.add_argument('-v', '--version', action='version', version='1.0') self.assertArgumentParserError(parser, '-h') self.assertArgumentParserError(parser, '--help') self.assertRaises(AttributeError, getattr, parser, 'format_version') def test_version_action(self): parser = ErrorRaisingArgumentParser(prog='XXX') parser.add_argument('-V', action='version', version='%(prog)s 3.7') - msg = self._get_error(parser.parse_args, ['-V']).stdout - self.assertEqual('XXX 3.7\n', msg) + with self.assertRaises(ArgumentParserError) as cm: + parser.parse_args(['-V']) + self.assertEqual('XXX 3.7\n', cm.exception.stdout) def test_no_help(self): parser = ErrorRaisingArgumentParser(add_help=False) self.assertArgumentParserError(parser, '-h') self.assertArgumentParserError(parser, '--help') self.assertArgumentParserError(parser, '-v') self.assertArgumentParserError(parser, '--version') @@ -4595,24 +4560,20 @@ class TestArgumentTypeError(TestCase): def test_argument_type_error(self): def spam(string): raise argparse.ArgumentTypeError('spam!') parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False) parser.add_argument('x', type=spam) - try: + with self.assertRaises(ArgumentParserError) as cm: parser.parse_args(['XXX']) - except ArgumentParserError: - expected = 'usage: PROG x\nPROG: error: argument x: spam!\n' - msg = sys.exc_info()[1].stderr - self.assertEqual(expected, msg) - else: - self.fail() + expected = 'usage: PROG x\nPROG: error: argument x: spam!\n' + self.assertEqual(expected, cm.exception.stderr) # ========================= # MessageContentError tests # ========================= class TestMessageContentError(TestCase): def test_missing_argument_name_in_message(self): diff --git a/Misc/ACKS b/Misc/ACKS --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1394,16 +1394,17 @@ Jacques A. Vidrine John Viega Dino Viehland Kannan Vijayan Kurt Vile Norman Vine Pauli Virtanen Frank Visser Johannes Vogel +Radu Voicilas Alex Volkov Martijn Vries Sjoerd de Vries Guido Vranken Niki W. Waibel Wojtek Walczak Charles Waldman Richard Walker diff --git a/Misc/NEWS b/Misc/NEWS --- a/Misc/NEWS +++ b/Misc/NEWS @@ -648,16 +648,19 @@ Documentation required reference material for tool developers that isn't recorded anywhere else. - Issue #19697: Document cases where __main__.__spec__ is None. Tests ----- +- Issue #9554: Use modern unittest features in test_argparse. Initial patch by + Denver Coneybeare and Radu Voicilas. + - Issue #20155: Changed HTTP method names in failing tests in test_httpservers so that packet filtering software (specifically Windows Base Filtering Engine) does not interfere with the transaction semantics expected by the tests. - Issue #19493: Refactored the ctypes test package to skip tests explicitly rather than silently. - Issue #18492: All resources are now allowed when tests are not run by