Skip to content

Commit 3c83f99

Browse files
gh-72795: Make positional arguments with nargs='*' or REMAINDER non-required (GH-124306)
This allows to use positional argument with nargs='*' and without default in mutually exclusive group and improves error message about required arguments.
1 parent c578271 commit 3c83f99

File tree

3 files changed

+32
-8
lines changed

3 files changed

+32
-8
lines changed

Lib/argparse.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,9 +1532,8 @@ def _get_positional_kwargs(self, dest, **kwargs):
15321532

15331533
# mark positional arguments as required if at least one is
15341534
# always required
1535-
if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
1536-
kwargs['required'] = True
1537-
if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
1535+
nargs = kwargs.get('nargs')
1536+
if nargs not in [OPTIONAL, ZERO_OR_MORE, REMAINDER, SUPPRESS, 0]:
15381537
kwargs['required'] = True
15391538

15401539
# return the keyword arguments with no option strings

Lib/test/test_argparse.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,7 +3079,7 @@ def get_parser(self, required):
30793079
group = parser.add_mutually_exclusive_group(required=required)
30803080
group.add_argument('--foo', action='store_true', help='FOO')
30813081
group.add_argument('--spam', help='SPAM')
3082-
group.add_argument('badger', nargs='*', default='X', help='BADGER')
3082+
group.add_argument('badger', nargs='*', help='BADGER')
30833083
return parser
30843084

30853085
failures = [
@@ -3090,13 +3090,13 @@ def get_parser(self, required):
30903090
'--foo X Y',
30913091
]
30923092
successes = [
3093-
('--foo', NS(foo=True, spam=None, badger='X')),
3094-
('--spam S', NS(foo=False, spam='S', badger='X')),
3093+
('--foo', NS(foo=True, spam=None, badger=[])),
3094+
('--spam S', NS(foo=False, spam='S', badger=[])),
30953095
('X', NS(foo=False, spam=None, badger=['X'])),
30963096
('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
30973097
]
30983098
successes_when_not_required = [
3099-
('', NS(foo=False, spam=None, badger='X')),
3099+
('', NS(foo=False, spam=None, badger=[])),
31003100
]
31013101

31023102
usage_when_not_required = '''\
@@ -6369,7 +6369,28 @@ def test_required_args(self):
63696369
self.parser.add_argument('bar')
63706370
self.parser.add_argument('baz')
63716371
self.assertRaisesRegex(argparse.ArgumentError,
6372-
'the following arguments are required: bar, baz',
6372+
'the following arguments are required: bar, baz$',
6373+
self.parser.parse_args, [])
6374+
6375+
def test_required_args_optional(self):
6376+
self.parser.add_argument('bar')
6377+
self.parser.add_argument('baz', nargs='?')
6378+
self.assertRaisesRegex(argparse.ArgumentError,
6379+
'the following arguments are required: bar$',
6380+
self.parser.parse_args, [])
6381+
6382+
def test_required_args_zero_or_more(self):
6383+
self.parser.add_argument('bar')
6384+
self.parser.add_argument('baz', nargs='*')
6385+
self.assertRaisesRegex(argparse.ArgumentError,
6386+
'the following arguments are required: bar$',
6387+
self.parser.parse_args, [])
6388+
6389+
def test_required_args_remainder(self):
6390+
self.parser.add_argument('bar')
6391+
self.parser.add_argument('baz', nargs='...')
6392+
self.assertRaisesRegex(argparse.ArgumentError,
6393+
'the following arguments are required: bar$',
63736394
self.parser.parse_args, [])
63746395

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

0 commit comments

Comments
 (0)