bpo-26510: make argparse subparsers required by default (#3027) · pythoncapi/cpython@aaf6fc0 · GitHub
Skip to content

Commit aaf6fc0

Browse files
asottilemerwok
authored andcommitted
bpo-26510: make argparse subparsers required by default (python#3027)
This fixes a regression from Python 2. To get optional subparsers, use the new parameter ``add_subparsers(required=False)``. Patch by Anthony Sottile.
1 parent 19e4d93 commit aaf6fc0

4 files changed

Lines changed: 46 additions & 3 deletions

File tree

Doc/library/argparse.rst

Lines changed: 5 additions & 2 deletions

Lib/argparse.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ def __init__(self,
10661066
prog,
10671067
parser_class,
10681068
dest=SUPPRESS,
1069+
required=True,
10691070
help=None,
10701071
metavar=None):
10711072

@@ -1079,6 +1080,7 @@ def __init__(self,
10791080
dest=dest,
10801081
nargs=PARSER,
10811082
choices=self._name_parser_map,
1083+
required=required,
10821084
help=help,
10831085
metavar=metavar)
10841086

Lib/test/test_argparse.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,7 @@ def _get_parser(self, subparser_help=False, prefix_chars=None,
18071807
'bar', type=float, help='bar help')
18081808

18091809
# check that only one subparsers argument can be added
1810-
subparsers_kwargs = {}
1810+
subparsers_kwargs = {'required': False}
18111811
if aliases:
18121812
subparsers_kwargs['metavar'] = 'COMMAND'
18131813
subparsers_kwargs['title'] = 'commands'
@@ -1907,6 +1907,41 @@ def test_dest(self):
19071907
self.assertEqual(NS(foo=False, bar='1', baz='2'),
19081908
parser.parse_args('1 2'.split()))
19091909

1910+
def _test_required_subparsers(self, parser):
1911+
# Should parse the sub command
1912+
ret = parser.parse_args(['run'])
1913+
self.assertEqual(ret.command, 'run')
1914+
1915+
# Error when the command is missing
1916+
self.assertArgumentParserError(parser.parse_args, ())
1917+
1918+
def test_required_subparsers_via_attribute(self):
1919+
parser = ErrorRaisingArgumentParser()
1920+
subparsers = parser.add_subparsers(dest='command')
1921+
subparsers.required = True
1922+
subparsers.add_parser('run')
1923+
self._test_required_subparsers(parser)
1924+
1925+
def test_required_subparsers_via_kwarg(self):
1926+
parser = ErrorRaisingArgumentParser()
1927+
subparsers = parser.add_subparsers(dest='command', required=True)
1928+
subparsers.add_parser('run')
1929+
self._test_required_subparsers(parser)
1930+
1931+
def test_required_subparsers_default(self):
1932+
parser = ErrorRaisingArgumentParser()
1933+
subparsers = parser.add_subparsers(dest='command')
1934+
subparsers.add_parser('run')
1935+
self._test_required_subparsers(parser)
1936+
1937+
def test_optional_subparsers(self):
1938+
parser = ErrorRaisingArgumentParser()
1939+
subparsers = parser.add_subparsers(dest='command', required=False)
1940+
subparsers.add_parser('run')
1941+
# No error here
1942+
ret = parser.parse_args(())
1943+
self.assertIsNone(ret.command)
1944+
19101945
def test_help(self):
19111946
self.assertEqual(self.parser.format_usage(),
19121947
'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Lines changed: 3 additions & 0 deletions

0 commit comments

Comments
 (0)