mirror of
https://github.com/python/cpython.git
synced 2025-10-14 10:53:40 +00:00
bpo-26510: make argparse subparsers required by default (#3027)
This fixes a regression from Python 2. To get optional subparsers, use the new parameter ``add_subparsers(required=False)``. Patch by Anthony Sottile.
This commit is contained in:
parent
19e4d9346d
commit
aaf6fc0982
4 changed files with 46 additions and 3 deletions
|
@ -1539,8 +1539,8 @@ Sub-commands
|
||||||
|
|
||||||
.. method:: ArgumentParser.add_subparsers([title], [description], [prog], \
|
.. method:: ArgumentParser.add_subparsers([title], [description], [prog], \
|
||||||
[parser_class], [action], \
|
[parser_class], [action], \
|
||||||
[option_string], [dest], [help], \
|
[option_string], [dest], [required] \
|
||||||
[metavar])
|
[help], [metavar])
|
||||||
|
|
||||||
Many programs split up their functionality into a number of sub-commands,
|
Many programs split up their functionality into a number of sub-commands,
|
||||||
for example, the ``svn`` program can invoke sub-commands like ``svn
|
for example, the ``svn`` program can invoke sub-commands like ``svn
|
||||||
|
@ -1576,6 +1576,9 @@ Sub-commands
|
||||||
* dest_ - name of the attribute under which sub-command name will be
|
* dest_ - name of the attribute under which sub-command name will be
|
||||||
stored; by default ``None`` and no value is stored
|
stored; by default ``None`` and no value is stored
|
||||||
|
|
||||||
|
* required_ - Whether or not a subcommand must be provided, by default
|
||||||
|
``True``.
|
||||||
|
|
||||||
* help_ - help for sub-parser group in help output, by default ``None``
|
* help_ - help for sub-parser group in help output, by default ``None``
|
||||||
|
|
||||||
* metavar_ - string presenting available sub-commands in help; by default it
|
* metavar_ - string presenting available sub-commands in help; by default it
|
||||||
|
|
|
@ -1066,6 +1066,7 @@ class _SubParsersAction(Action):
|
||||||
prog,
|
prog,
|
||||||
parser_class,
|
parser_class,
|
||||||
dest=SUPPRESS,
|
dest=SUPPRESS,
|
||||||
|
required=True,
|
||||||
help=None,
|
help=None,
|
||||||
metavar=None):
|
metavar=None):
|
||||||
|
|
||||||
|
@ -1079,6 +1080,7 @@ class _SubParsersAction(Action):
|
||||||
dest=dest,
|
dest=dest,
|
||||||
nargs=PARSER,
|
nargs=PARSER,
|
||||||
choices=self._name_parser_map,
|
choices=self._name_parser_map,
|
||||||
|
required=required,
|
||||||
help=help,
|
help=help,
|
||||||
metavar=metavar)
|
metavar=metavar)
|
||||||
|
|
||||||
|
|
|
@ -1807,7 +1807,7 @@ class TestAddSubparsers(TestCase):
|
||||||
'bar', type=float, help='bar help')
|
'bar', type=float, help='bar help')
|
||||||
|
|
||||||
# check that only one subparsers argument can be added
|
# check that only one subparsers argument can be added
|
||||||
subparsers_kwargs = {}
|
subparsers_kwargs = {'required': False}
|
||||||
if aliases:
|
if aliases:
|
||||||
subparsers_kwargs['metavar'] = 'COMMAND'
|
subparsers_kwargs['metavar'] = 'COMMAND'
|
||||||
subparsers_kwargs['title'] = 'commands'
|
subparsers_kwargs['title'] = 'commands'
|
||||||
|
@ -1907,6 +1907,41 @@ class TestAddSubparsers(TestCase):
|
||||||
self.assertEqual(NS(foo=False, bar='1', baz='2'),
|
self.assertEqual(NS(foo=False, bar='1', baz='2'),
|
||||||
parser.parse_args('1 2'.split()))
|
parser.parse_args('1 2'.split()))
|
||||||
|
|
||||||
|
def _test_required_subparsers(self, parser):
|
||||||
|
# Should parse the sub command
|
||||||
|
ret = parser.parse_args(['run'])
|
||||||
|
self.assertEqual(ret.command, 'run')
|
||||||
|
|
||||||
|
# Error when the command is missing
|
||||||
|
self.assertArgumentParserError(parser.parse_args, ())
|
||||||
|
|
||||||
|
def test_required_subparsers_via_attribute(self):
|
||||||
|
parser = ErrorRaisingArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest='command')
|
||||||
|
subparsers.required = True
|
||||||
|
subparsers.add_parser('run')
|
||||||
|
self._test_required_subparsers(parser)
|
||||||
|
|
||||||
|
def test_required_subparsers_via_kwarg(self):
|
||||||
|
parser = ErrorRaisingArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest='command', required=True)
|
||||||
|
subparsers.add_parser('run')
|
||||||
|
self._test_required_subparsers(parser)
|
||||||
|
|
||||||
|
def test_required_subparsers_default(self):
|
||||||
|
parser = ErrorRaisingArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest='command')
|
||||||
|
subparsers.add_parser('run')
|
||||||
|
self._test_required_subparsers(parser)
|
||||||
|
|
||||||
|
def test_optional_subparsers(self):
|
||||||
|
parser = ErrorRaisingArgumentParser()
|
||||||
|
subparsers = parser.add_subparsers(dest='command', required=False)
|
||||||
|
subparsers.add_parser('run')
|
||||||
|
# No error here
|
||||||
|
ret = parser.parse_args(())
|
||||||
|
self.assertIsNone(ret.command)
|
||||||
|
|
||||||
def test_help(self):
|
def test_help(self):
|
||||||
self.assertEqual(self.parser.format_usage(),
|
self.assertEqual(self.parser.format_usage(),
|
||||||
'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
|
'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
argparse subparsers are now required by default. This matches behaviour in Python 2.
|
||||||
|
For optional subparsers, use the new parameter ``add_subparsers(required=False)``.
|
||||||
|
Patch by Anthony Sottile.
|
Loading…
Add table
Add a link
Reference in a new issue