X Tutup
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,34 @@ be achieved by specifying the ``namespace=`` keyword argument::
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
^^^^^^^^^^^^

Expand Down
13 changes: 13 additions & 0 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,7 @@ def __init__(self,
self._positionals = add_group(_('positional arguments'))
self._optionals = add_group(_('options'))
self._subparsers = None
self._disabled_interspersed_args = False

# register types
def identity(string):
Expand All @@ -1750,6 +1751,12 @@ def identity(string):
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
# =======================
Expand Down Expand Up @@ -2035,13 +2042,19 @@ def consume_positionals(start_index):
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
next_option_string_index = min([
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)

Expand Down
53 changes: 53 additions & 0 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1824,6 +1824,59 @@ def get_my_type(string):
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
# ============
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ Erik Tollerud
Stephen Tonkin
Matias Torchinsky
Sandro Tosi
Laszlo Attila Toth
Richard Townsend
David Townshend
Nathan Trapuzzano
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add argparse.ArgumentParser.disable_interspersed_args() and
enable_interspersed_args() based on optparse.OptionParser's similar methods.
X Tutup