diff -r 49130b06e3ac Doc/library/argparse.rst
--- a/Doc/library/argparse.rst Sun Feb 22 16:15:14 2015 -0800
+++ b/Doc/library/argparse.rst Sat Feb 28 14:30:18 2015 +0100
@@ -1512,6 +1512,34 @@
Other utilities
---------------
+Handling interspersed arguments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. method:: ArgumentParser.disable_interspersed_args()
+
+ Set parsing to stop on the first non-option. For example, if ``-a`` and
+ ``-b`` are both simple options that take no arguments, :mod:`optparse`
+ normally accepts this syntax::
+
+ prog -a arg1 -b arg2
+
+ and treats it as equivalent to ::
+
+ prog -a -b arg1 arg2
+
+ To disable this feature, call :meth:`disable_interspersed_args`. This
+ restores traditional Unix syntax, where option parsing stops with the first
+ non-option argument.
+
+ Use this if you have a command processor which runs another command which has
+ options of its own and you want to make sure these options don't get
+ confused. For example, each command might have a different set of options.
+
+.. method:: ArgumentParser.enable_interspersed_args()
+
+ Set parsing to not stop on the first non-option, allowing interspersing
+ switches with command arguments. This is the default behavior.
+
Sub-commands
^^^^^^^^^^^^
diff -r 49130b06e3ac Lib/argparse.py
--- a/Lib/argparse.py Sun Feb 22 16:15:14 2015 -0800
+++ b/Lib/argparse.py Sat Feb 28 14:30:18 2015 +0100
@@ -1629,6 +1629,7 @@
self._positionals = add_group(_('positional arguments'))
self._optionals = add_group(_('optional arguments'))
self._subparsers = None
+ self._disabled_interspersed_args = False
# register types
def identity(string):
@@ -1654,6 +1655,12 @@
else:
self._defaults.update(defaults)
+ def disable_interspersed_args(self):
+ self._disabled_interspersed_args = True
+
+ def enable_interspersed_args(self):
+ self._disabled_interspersed_args = False
+
# =======================
# Pretty __repr__ methods
# =======================
@@ -1935,6 +1942,7 @@
max_option_string_index = max(option_string_indices)
else:
max_option_string_index = -1
+
while start_index <= max_option_string_index:
# consume any Positionals preceding the next option
@@ -1942,6 +1950,11 @@
index
for index in option_string_indices
if index >= start_index])
+
+ if self._disabled_interspersed_args and next_option_string_index != start_index:
+ arg_strings_pattern = arg_strings_pattern[:start_index] + "A" * (len(arg_strings_pattern) - start_index)
+ break
+
if start_index != next_option_string_index:
positionals_end_index = consume_positionals(start_index)
diff -r 49130b06e3ac Lib/test/test_argparse.py
--- a/Lib/test/test_argparse.py Sun Feb 22 16:15:14 2015 -0800
+++ b/Lib/test/test_argparse.py Sat Feb 28 14:30:18 2015 +0100
@@ -1691,6 +1691,59 @@
NS(x='my_type{1}', y='my_type{42}'))
+# ===============================
+# Test Interspersed args and '--'
+# ===============================
+
+class TestInterspersedArgs(TestCase):
+ def setUp(self):
+ self.parser = ErrorRaisingArgumentParser()
+ self.parser.add_argument('-a', action='store_true')
+ self.parser.add_argument('foo')
+ self.parser.add_argument('rem', nargs='*')
+
+ def test_simple(self):
+ self.assertEqual(self.parser.parse_args('-a 3 5 6 9'.split()),
+ NS(a=True, foo='3', rem=['5', '6', '9']))
+ self.assertEqual(self.parser.parse_args('3 -a'.split()),
+ NS(a=True, foo='3', rem=[]))
+ self.assertEqual(self.parser.parse_args('3 4 5 -a'.split()),
+ NS(a=True, foo='3', rem=['4', '5']))
+
+ def test_hyphens(self):
+ self.assertEqual(self.parser.parse_args('-a -- 3 5 6 9'.split()),
+ NS(a=True, foo='3', rem=['5', '6', '9']))
+ self.assertEqual(self.parser.parse_args('-- 3 -a'.split()),
+ NS(a=False, foo='3', rem=['-a']))
+ self.assertEqual(self.parser.parse_args('-- 3 4 5 -a'.split()),
+ NS(a=False, foo='3', rem=['4', '5', '-a']))
+
+ def test_interspersed_args(self):
+ self.parser.disable_interspersed_args()
+ self.assertEqual(self.parser.parse_args('-a 3 5 6 9'.split()),
+ NS(a=True, foo='3', rem=['5', '6', '9']))
+ self.assertEqual(self.parser.parse_args('3 -a'.split()),
+ NS(a=False, foo='3', rem=['-a']))
+ self.assertEqual(self.parser.parse_args('3 4 5 -a'.split()),
+ NS(a=False, foo='3', rem=['4', '5', '-a']))
+
+ self.parser.enable_interspersed_args()
+ self.assertEqual(self.parser.parse_args('3 4 5 -a'.split()),
+ NS(a=True, foo='3', rem=['4', '5']))
+
+ def test_with_remainder(self):
+ self.parser = ErrorRaisingArgumentParser()
+ self.parser.add_argument('-a', action='store_true')
+ self.parser.add_argument('-b')
+ self.parser.add_argument('rem', nargs=argparse.REMAINDER)
+ self.assertEqual(self.parser.parse_args('-b 4 -a c -b 5'.split()),
+ NS(a=True, b='4', rem=['c', '-b', '5']))
+
+ self.parser.disable_interspersed_args()
+ self.assertEqual(self.parser.parse_args('-b 4 -a c -b 5'.split()),
+ NS(a=True, b='4', rem=['c', '-b', '5']))
+
+
# ============
# Action tests
# ============
diff -r 49130b06e3ac Misc/ACKS
--- a/Misc/ACKS Sun Feb 22 16:15:14 2015 -0800
+++ b/Misc/ACKS Sat Feb 28 14:30:18 2015 +0100
@@ -1391,6 +1391,7 @@
Stephen Tonkin
Matias Torchinsky
Sandro Tosi
+László Attila Tóth
Richard Townsend
David Townshend
Nathan Trapuzzano
diff -r 49130b06e3ac Misc/NEWS
--- a/Misc/NEWS Sun Feb 22 16:15:14 2015 -0800
+++ b/Misc/NEWS Sat Feb 28 14:30:18 2015 +0100
@@ -65,6 +65,9 @@
argument which, if set to True, will pass messages to handlers taking handler
levels into account.
+- Issue #13966: Add argparse.ArgumentParser.disable_interspersed_args() and
+ enable_interspersed_args() based on optparse.OptionParser's similar methods.
+
Build
-----