Skip to content

Commit a2e5f41

Browse files
serhiy-storchakasavannahostrowski
authored andcommitted
pythongh-81691: Fix handling of multiple "--" (double dashes) in argparse (pythonGH-124233)
Only the first one has now been removed, all subsequent ones are now taken literally.
1 parent 1c59891 commit a2e5f41

File tree

3 files changed

+67
-8
lines changed

3 files changed

+67
-8
lines changed

Lib/argparse.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,11 @@ def consume_positionals(start_index):
20692069
# and add the Positional and its args to the list
20702070
for action, arg_count in zip(positionals, arg_counts):
20712071
args = arg_strings[start_index: start_index + arg_count]
2072+
# Strip out the first '--' if it is not in PARSER or REMAINDER arg.
2073+
if (action.nargs not in [PARSER, REMAINDER]
2074+
and arg_strings_pattern.find('-', start_index,
2075+
start_index + arg_count) >= 0):
2076+
args.remove('--')
20722077
start_index += arg_count
20732078
if args and action.deprecated and action.dest not in warned:
20742079
self._warning(_("argument '%(argument_name)s' is deprecated") %
@@ -2469,13 +2474,6 @@ def parse_known_intermixed_args(self, args=None, namespace=None):
24692474
# Value conversion methods
24702475
# ========================
24712476
def _get_values(self, action, arg_strings):
2472-
# for everything but PARSER, REMAINDER args, strip out first '--'
2473-
if not action.option_strings and action.nargs not in [PARSER, REMAINDER]:
2474-
try:
2475-
arg_strings.remove('--')
2476-
except ValueError:
2477-
pass
2478-
24792477
# optional argument produces a default when not present
24802478
if not arg_strings and action.nargs == OPTIONAL:
24812479
if action.option_strings:

Lib/test/test_argparse.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5761,7 +5761,30 @@ def test_zero_or_more_optional(self):
57615761
self.assertEqual(NS(x=[]), args)
57625762

57635763
def test_double_dash(self):
5764-
parser = argparse.ArgumentParser()
5764+
parser = argparse.ArgumentParser(exit_on_error=False)
5765+
parser.add_argument('-f', '--foo')
5766+
parser.add_argument('bar', nargs='*')
5767+
5768+
args = parser.parse_args(['--foo=--'])
5769+
self.assertEqual(NS(foo='--', bar=[]), args)
5770+
self.assertRaisesRegex(argparse.ArgumentError,
5771+
'argument -f/--foo: expected one argument',
5772+
parser.parse_args, ['--foo', '--'])
5773+
args = parser.parse_args(['-f--'])
5774+
self.assertEqual(NS(foo='--', bar=[]), args)
5775+
self.assertRaisesRegex(argparse.ArgumentError,
5776+
'argument -f/--foo: expected one argument',
5777+
parser.parse_args, ['-f', '--'])
5778+
args = parser.parse_args(['--foo', 'a', '--', 'b', 'c'])
5779+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5780+
args = parser.parse_args(['a', 'b', '--foo', 'c'])
5781+
self.assertEqual(NS(foo='c', bar=['a', 'b']), args)
5782+
args = parser.parse_args(['a', '--', 'b', '--foo', 'c'])
5783+
self.assertEqual(NS(foo=None, bar=['a', 'b', '--foo', 'c']), args)
5784+
args = parser.parse_args(['a', '--', 'b', '--', 'c', '--foo', 'd'])
5785+
self.assertEqual(NS(foo=None, bar=['a', 'b', '--', 'c', '--foo', 'd']), args)
5786+
5787+
parser = argparse.ArgumentParser(exit_on_error=False)
57655788
parser.add_argument('-f', '--foo', nargs='*')
57665789
parser.add_argument('bar', nargs='*')
57675790

@@ -5775,6 +5798,41 @@ def test_double_dash(self):
57755798
self.assertEqual(NS(foo=[], bar=[]), args)
57765799
args = parser.parse_args(['--foo', 'a', 'b', '--', 'c', 'd'])
57775800
self.assertEqual(NS(foo=['a', 'b'], bar=['c', 'd']), args)
5801+
args = parser.parse_args(['a', 'b', '--foo', 'c', 'd'])
5802+
self.assertEqual(NS(foo=['c', 'd'], bar=['a', 'b']), args)
5803+
args = parser.parse_args(['a', '--', 'b', '--foo', 'c', 'd'])
5804+
self.assertEqual(NS(foo=None, bar=['a', 'b', '--foo', 'c', 'd']), args)
5805+
args, argv = parser.parse_known_args(['a', 'b', '--foo', 'c', '--', 'd'])
5806+
self.assertEqual(NS(foo=['c'], bar=['a', 'b']), args)
5807+
self.assertEqual(argv, ['--', 'd'])
5808+
5809+
parser = argparse.ArgumentParser(exit_on_error=False)
5810+
parser.add_argument('foo')
5811+
parser.add_argument('bar', nargs='*')
5812+
5813+
args = parser.parse_args(['--', 'a', 'b', 'c'])
5814+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5815+
args = parser.parse_args(['a', '--', 'b', 'c'])
5816+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5817+
args = parser.parse_args(['a', 'b', '--', 'c'])
5818+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5819+
args = parser.parse_args(['a', '--', 'b', '--', 'c'])
5820+
self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args)
5821+
args = parser.parse_args(['--', '--', 'a', '--', 'b', 'c'])
5822+
self.assertEqual(NS(foo='--', bar=['a', '--', 'b', 'c']), args)
5823+
5824+
parser = argparse.ArgumentParser(exit_on_error=False)
5825+
parser.add_argument('foo')
5826+
parser.add_argument('bar', nargs=argparse.REMAINDER)
5827+
5828+
args = parser.parse_args(['--', 'a', 'b', 'c'])
5829+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5830+
args = parser.parse_args(['a', '--', 'b', 'c'])
5831+
self.assertEqual(NS(foo='a', bar=['b', 'c']), args)
5832+
args = parser.parse_args(['a', 'b', '--', 'c'])
5833+
self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args)
5834+
args = parser.parse_args(['a', '--', 'b', '--', 'c'])
5835+
self.assertEqual(NS(foo='a', bar=['b', '--', 'c']), args)
57785836

57795837

57805838
# ===========================
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix handling of multiple ``"--"`` (double dashes) in :mod:`argparse`. Only
2+
the first one has now been removed, all subsequent ones are now taken
3+
literally.

0 commit comments

Comments
 (0)