Skip to content

Commit

Permalink
gh-72795: Make positional arguments with nargs='*' or REMAINDER non-r…
Browse files Browse the repository at this point in the history
…equired (GH-124306)

This allows to use positional argument with nargs='*' and without default
in mutually exclusive group and improves error message about required
arguments.
  • Loading branch information
serhiy-storchaka authored Sep 24, 2024
1 parent c578271 commit 3c83f99
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 8 deletions.
5 changes: 2 additions & 3 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1532,9 +1532,8 @@ def _get_positional_kwargs(self, dest, **kwargs):

# mark positional arguments as required if at least one is
# always required
if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
kwargs['required'] = True
if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
nargs = kwargs.get('nargs')
if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS, 0]:
kwargs['required'] = True

# return the keyword arguments with no option strings
Expand Down
31 changes: 26 additions & 5 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -3079,7 +3079,7 @@ def get_parser(self, required):
group = parser.add_mutually_exclusive_group(required=required)
group.add_argument('--foo', action='store_true', help='FOO')
group.add_argument('--spam', help='SPAM')
group.add_argument('badger', nargs='*', default='X', help='BADGER')
group.add_argument('badger', nargs='*', help='BADGER')
return parser

failures = [
Expand All @@ -3090,13 +3090,13 @@ def get_parser(self, required):
'--foo X Y',
]
successes = [
('--foo', NS(foo=True, spam=None, badger='X')),
('--spam S', NS(foo=False, spam='S', badger='X')),
('--foo', NS(foo=True, spam=None, badger=[])),
('--spam S', NS(foo=False, spam='S', badger=[])),
('X', NS(foo=False, spam=None, badger=['X'])),
('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
]
successes_when_not_required = [
('', NS(foo=False, spam=None, badger='X')),
('', NS(foo=False, spam=None, badger=[])),
]

usage_when_not_required = '''\
Expand Down Expand Up @@ -6369,7 +6369,28 @@ def test_required_args(self):
self.parser.add_argument('bar')
self.parser.add_argument('baz')
self.assertRaisesRegex(argparse.ArgumentError,
'the following arguments are required: bar, baz',
'the following arguments are required: bar, baz$',
self.parser.parse_args, [])

def test_required_args_optional(self):
self.parser.add_argument('bar')
self.parser.add_argument('baz', nargs='?')
self.assertRaisesRegex(argparse.ArgumentError,
'the following arguments are required: bar$',
self.parser.parse_args, [])

def test_required_args_zero_or_more(self):
self.parser.add_argument('bar')
self.parser.add_argument('baz', nargs='*')
self.assertRaisesRegex(argparse.ArgumentError,
'the following arguments are required: bar$',
self.parser.parse_args, [])

def test_required_args_remainder(self):
self.parser.add_argument('bar')
self.parser.add_argument('baz', nargs='...')
self.assertRaisesRegex(argparse.ArgumentError,
'the following arguments are required: bar$',
self.parser.parse_args, [])

def test_required_mutually_exclusive_args(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Positional arguments with :ref:`nargs` equal to ``'*'`` or
:data:`!argparse.REMAINDER` are no longer required. This allows to use
positional argument with ``nargs='*'`` and without ``default`` in mutually
exclusive group and improves error message about required arguments.

0 comments on commit 3c83f99

Please sign in to comment.