summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorR. David Murray <rdmurray@bitdance.com>2017-09-07 00:25:40 (GMT)
committerGitHub <noreply@github.com>2017-09-07 00:25:40 (GMT)
commit0f6b9d230674da784ca79a0cf1a03d2af5a8b6a8 (patch)
treebe36691f027da9af59e6ae400b7608a5f28794e8 /Lib/test
parentad0ffa033ea79f7c7cb14b1b1cc10888ea9e9913 (diff)
downloadcpython-0f6b9d230674da784ca79a0cf1a03d2af5a8b6a8.zip
cpython-0f6b9d230674da784ca79a0cf1a03d2af5a8b6a8.tar.gz
cpython-0f6b9d230674da784ca79a0cf1a03d2af5a8b6a8.tar.bz2
bpo-14191 Add parse_intermixed_args. (#3319)
This adds support for parsing a command line where options and positionals are intermixed as is common in many unix commands. This is paul.j3's patch with a few tweaks.
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_argparse.py87
1 files changed, 87 insertions, 0 deletions
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 9c27f64..d8bcd73 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -4804,6 +4804,93 @@ class TestParseKnownArgs(TestCase):
self.assertEqual(NS(v=3, spam=True, badger="B"), args)
self.assertEqual(["C", "--foo", "4"], extras)
+# ===========================
+# parse_intermixed_args tests
+# ===========================
+
+class TestIntermixedArgs(TestCase):
+ def test_basic(self):
+ # test parsing intermixed optionals and positionals
+ parser = argparse.ArgumentParser(prog='PROG')
+ parser.add_argument('--foo', dest='foo')
+ bar = parser.add_argument('--bar', dest='bar', required=True)
+ parser.add_argument('cmd')
+ parser.add_argument('rest', nargs='*', type=int)
+ argv = 'cmd --foo x 1 --bar y 2 3'.split()
+ args = parser.parse_intermixed_args(argv)
+ # rest gets [1,2,3] despite the foo and bar strings
+ self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args)
+
+ args, extras = parser.parse_known_args(argv)
+ # cannot parse the '1,2,3'
+ self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[]), args)
+ self.assertEqual(["1", "2", "3"], extras)
+
+ argv = 'cmd --foo x 1 --error 2 --bar y 3'.split()
+ args, extras = parser.parse_known_intermixed_args(argv)
+ # unknown optionals go into extras
+ self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args)
+ self.assertEqual(['--error', '2', '3'], extras)
+
+ # restores attributes that were temporarily changed
+ self.assertIsNone(parser.usage)
+ self.assertEqual(bar.required, True)
+
+ def test_remainder(self):
+ # Intermixed and remainder are incompatible
+ parser = ErrorRaisingArgumentParser(prog='PROG')
+ parser.add_argument('-z')
+ parser.add_argument('x')
+ parser.add_argument('y', nargs='...')
+ argv = 'X A B -z Z'.split()
+ # intermixed fails with '...' (also 'A...')
+ # self.assertRaises(TypeError, parser.parse_intermixed_args, argv)
+ with self.assertRaises(TypeError) as cm:
+ parser.parse_intermixed_args(argv)
+ self.assertRegex(str(cm.exception), r'\.\.\.')
+
+ def test_exclusive(self):
+ # mutually exclusive group; intermixed works fine
+ parser = ErrorRaisingArgumentParser(prog='PROG')
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('--foo', action='store_true', help='FOO')
+ group.add_argument('--spam', help='SPAM')
+ parser.add_argument('badger', nargs='*', default='X', help='BADGER')
+ args = parser.parse_intermixed_args('1 --foo 2'.split())
+ self.assertEqual(NS(badger=['1', '2'], foo=True, spam=None), args)
+ self.assertRaises(ArgumentParserError, parser.parse_intermixed_args, '1 2'.split())
+ self.assertEqual(group.required, True)
+
+ def test_exclusive_incompatible(self):
+ # mutually exclusive group including positional - fail
+ parser = ErrorRaisingArgumentParser(prog='PROG')
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('--foo', action='store_true', help='FOO')
+ group.add_argument('--spam', help='SPAM')
+ group.add_argument('badger', nargs='*', default='X', help='BADGER')
+ self.assertRaises(TypeError, parser.parse_intermixed_args, [])
+ self.assertEqual(group.required, True)
+
+class TestIntermixedMessageContentError(TestCase):
+ # case where Intermixed gives different error message
+ # error is raised by 1st parsing step
+ def test_missing_argument_name_in_message(self):
+ parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
+ parser.add_argument('req_pos', type=str)
+ parser.add_argument('-req_opt', type=int, required=True)
+
+ with self.assertRaises(ArgumentParserError) as cm:
+ parser.parse_args([])
+ msg = str(cm.exception)
+ self.assertRegex(msg, 'req_pos')
+ self.assertRegex(msg, 'req_opt')
+
+ with self.assertRaises(ArgumentParserError) as cm:
+ parser.parse_intermixed_args([])
+ msg = str(cm.exception)
+ self.assertNotRegex(msg, 'req_pos')
+ self.assertRegex(msg, 'req_opt')
+
# ==========================
# add_argument metavar tests
# ==========================