mirror of https://github.com/python/cpython
Issue #12713: reverted fix pending further discussion.
This commit is contained in:
parent
d1c2a8e2b5
commit
9ae505041f
|
@ -1668,18 +1668,6 @@ Sub-commands
|
||||||
>>> parser.parse_args(['co', 'bar'])
|
>>> parser.parse_args(['co', 'bar'])
|
||||||
Namespace(foo='bar')
|
Namespace(foo='bar')
|
||||||
|
|
||||||
argparse supports non-ambiguous abbreviations of subparser names.
|
|
||||||
|
|
||||||
For example, the following three calls are all supported
|
|
||||||
and do the same thing, as the abbreviations used are not ambiguous::
|
|
||||||
|
|
||||||
>>> parser.parse_args(['checkout', 'bar'])
|
|
||||||
Namespace(foo='bar')
|
|
||||||
>>> parser.parse_args(['check', 'bar'])
|
|
||||||
Namespace(foo='bar')
|
|
||||||
>>> parser.parse_args(['che', 'bar'])
|
|
||||||
Namespace(foo='bar')
|
|
||||||
|
|
||||||
One particularly effective way of handling sub-commands is to combine the use
|
One particularly effective way of handling sub-commands is to combine the use
|
||||||
of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
|
of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
|
||||||
that each subparser knows which Python function it should execute. For
|
that each subparser knows which Python function it should execute. For
|
||||||
|
|
|
@ -1110,12 +1110,6 @@ class _SubParsersAction(Action):
|
||||||
parser_name = values[0]
|
parser_name = values[0]
|
||||||
arg_strings = values[1:]
|
arg_strings = values[1:]
|
||||||
|
|
||||||
# get full parser_name from (optional) abbreviated one
|
|
||||||
for p in self._name_parser_map:
|
|
||||||
if p.startswith(parser_name):
|
|
||||||
parser_name = p
|
|
||||||
break
|
|
||||||
|
|
||||||
# set the parser name if requested
|
# set the parser name if requested
|
||||||
if self.dest is not SUPPRESS:
|
if self.dest is not SUPPRESS:
|
||||||
setattr(namespace, self.dest, parser_name)
|
setattr(namespace, self.dest, parser_name)
|
||||||
|
@ -2313,18 +2307,11 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
|
||||||
|
|
||||||
def _check_value(self, action, value):
|
def _check_value(self, action, value):
|
||||||
# converted value must be one of the choices (if specified)
|
# converted value must be one of the choices (if specified)
|
||||||
if action.choices is not None:
|
if action.choices is not None and value not in action.choices:
|
||||||
ac = [ax for ax in action.choices if str(ax).startswith(str(value))]
|
args = {'value': value,
|
||||||
if len(ac) == 0:
|
'choices': ', '.join(map(repr, action.choices))}
|
||||||
args = {'value': value,
|
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
|
||||||
'choices': ', '.join(map(repr, action.choices))}
|
raise ArgumentError(action, msg % args)
|
||||||
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
|
|
||||||
raise ArgumentError(action, msg % args)
|
|
||||||
elif len(ac) > 1:
|
|
||||||
args = {'value': value,
|
|
||||||
'choices': ', '.join(ac)}
|
|
||||||
msg = _('ambiguous choice: %(value)r could match %(choices)s')
|
|
||||||
raise ArgumentError(action, msg % args)
|
|
||||||
|
|
||||||
# =======================
|
# =======================
|
||||||
# Help-formatting methods
|
# Help-formatting methods
|
||||||
|
|
|
@ -1842,22 +1842,6 @@ class TestAddSubparsers(TestCase):
|
||||||
parser3.add_argument('t', type=int, help='t help')
|
parser3.add_argument('t', type=int, help='t help')
|
||||||
parser3.add_argument('u', nargs='...', help='u help')
|
parser3.add_argument('u', nargs='...', help='u help')
|
||||||
|
|
||||||
# add fourth sub-parser (to test abbreviations)
|
|
||||||
parser4_kwargs = dict(description='lost description')
|
|
||||||
if subparser_help:
|
|
||||||
parser4_kwargs['help'] = 'lost help'
|
|
||||||
parser4 = subparsers.add_parser('lost', **parser4_kwargs)
|
|
||||||
parser4.add_argument('-w', type=int, help='w help')
|
|
||||||
parser4.add_argument('x', choices='abc', help='x help')
|
|
||||||
|
|
||||||
# add fifth sub-parser, with longer name (to test abbreviations)
|
|
||||||
parser5_kwargs = dict(description='long description')
|
|
||||||
if subparser_help:
|
|
||||||
parser5_kwargs['help'] = 'long help'
|
|
||||||
parser5 = subparsers.add_parser('long', **parser5_kwargs)
|
|
||||||
parser5.add_argument('-w', type=int, help='w help')
|
|
||||||
parser5.add_argument('x', choices='abc', help='x help')
|
|
||||||
|
|
||||||
# return the main parser
|
# return the main parser
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
@ -1873,24 +1857,6 @@ class TestAddSubparsers(TestCase):
|
||||||
args = args_str.split()
|
args = args_str.split()
|
||||||
self.assertArgumentParserError(self.parser.parse_args, args)
|
self.assertArgumentParserError(self.parser.parse_args, args)
|
||||||
|
|
||||||
def test_parse_args_abbreviation(self):
|
|
||||||
# check some non-failure cases:
|
|
||||||
self.assertEqual(
|
|
||||||
self.parser.parse_args('0.5 long b -w 7'.split()),
|
|
||||||
NS(foo=False, bar=0.5, w=7, x='b'),
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.parser.parse_args('0.5 lon b -w 7'.split()),
|
|
||||||
NS(foo=False, bar=0.5, w=7, x='b'),
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
self.parser.parse_args('0.5 los b -w 7'.split()),
|
|
||||||
NS(foo=False, bar=0.5, w=7, x='b'),
|
|
||||||
)
|
|
||||||
# check a failure case: 'lo' is ambiguous
|
|
||||||
self.assertArgumentParserError(self.parser.parse_args,
|
|
||||||
'0.5 lo b -w 7'.split())
|
|
||||||
|
|
||||||
def test_parse_args(self):
|
def test_parse_args(self):
|
||||||
# check some non-failure cases:
|
# check some non-failure cases:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -1943,80 +1909,78 @@ class TestAddSubparsers(TestCase):
|
||||||
|
|
||||||
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,lost,long} ...\n')
|
'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
|
||||||
self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
|
self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
|
||||||
usage: PROG [-h] [--foo] bar {1,2,3,lost,long} ...
|
usage: PROG [-h] [--foo] bar {1,2,3} ...
|
||||||
|
|
||||||
main description
|
main description
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
bar bar help
|
bar bar help
|
||||||
{1,2,3,lost,long} command help
|
{1,2,3} command help
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
--foo foo help
|
--foo foo help
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
def test_help_extra_prefix_chars(self):
|
def test_help_extra_prefix_chars(self):
|
||||||
# Make sure - is still used for help if it is a non-first prefix char
|
# Make sure - is still used for help if it is a non-first prefix char
|
||||||
parser = self._get_parser(prefix_chars='+:-')
|
parser = self._get_parser(prefix_chars='+:-')
|
||||||
self.assertEqual(parser.format_usage(),
|
self.assertEqual(parser.format_usage(),
|
||||||
'usage: PROG [-h] [++foo] bar {1,2,3,lost,long} ...\n')
|
'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
|
||||||
self.assertEqual(parser.format_help(), textwrap.dedent('''\
|
self.assertEqual(parser.format_help(), textwrap.dedent('''\
|
||||||
usage: PROG [-h] [++foo] bar {1,2,3,lost,long} ...
|
usage: PROG [-h] [++foo] bar {1,2,3} ...
|
||||||
|
|
||||||
main description
|
main description
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
bar bar help
|
bar bar help
|
||||||
{1,2,3,lost,long} command help
|
{1,2,3} command help
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
++foo foo help
|
++foo foo help
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
|
|
||||||
def test_help_alternate_prefix_chars(self):
|
def test_help_alternate_prefix_chars(self):
|
||||||
parser = self._get_parser(prefix_chars='+:/')
|
parser = self._get_parser(prefix_chars='+:/')
|
||||||
self.assertEqual(parser.format_usage(),
|
self.assertEqual(parser.format_usage(),
|
||||||
'usage: PROG [+h] [++foo] bar {1,2,3,lost,long} ...\n')
|
'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
|
||||||
self.assertEqual(parser.format_help(), textwrap.dedent('''\
|
self.assertEqual(parser.format_help(), textwrap.dedent('''\
|
||||||
usage: PROG [+h] [++foo] bar {1,2,3,lost,long} ...
|
usage: PROG [+h] [++foo] bar {1,2,3} ...
|
||||||
|
|
||||||
main description
|
main description
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
bar bar help
|
bar bar help
|
||||||
{1,2,3,lost,long} command help
|
{1,2,3} command help
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
+h, ++help show this help message and exit
|
+h, ++help show this help message and exit
|
||||||
++foo foo help
|
++foo foo help
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
def test_parser_command_help(self):
|
def test_parser_command_help(self):
|
||||||
self.assertEqual(self.command_help_parser.format_usage(),
|
self.assertEqual(self.command_help_parser.format_usage(),
|
||||||
'usage: PROG [-h] [--foo] bar {1,2,3,lost,long} ...\n')
|
'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
|
||||||
self.assertEqual(self.command_help_parser.format_help(),
|
self.assertEqual(self.command_help_parser.format_help(),
|
||||||
textwrap.dedent('''\
|
textwrap.dedent('''\
|
||||||
usage: PROG [-h] [--foo] bar {1,2,3,lost,long} ...
|
usage: PROG [-h] [--foo] bar {1,2,3} ...
|
||||||
|
|
||||||
main description
|
main description
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
bar bar help
|
bar bar help
|
||||||
{1,2,3,lost,long} command help
|
{1,2,3} command help
|
||||||
1 1 help
|
1 1 help
|
||||||
2 2 help
|
2 2 help
|
||||||
3 3 help
|
3 3 help
|
||||||
lost lost help
|
|
||||||
long long help
|
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
--foo foo help
|
--foo foo help
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
def test_subparser_title_help(self):
|
def test_subparser_title_help(self):
|
||||||
|
@ -2119,8 +2083,6 @@ class TestAddSubparsers(TestCase):
|
||||||
1 help
|
1 help
|
||||||
2 2 help
|
2 2 help
|
||||||
3 3 help
|
3 3 help
|
||||||
lost lost help
|
|
||||||
long long help
|
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
# ============
|
# ============
|
||||||
|
|
|
@ -60,9 +60,6 @@ Library
|
||||||
- Issue #9998: On Linux, ctypes.util.find_library now looks in LD_LIBRARY_PATH
|
- Issue #9998: On Linux, ctypes.util.find_library now looks in LD_LIBRARY_PATH
|
||||||
for shared libraries.
|
for shared libraries.
|
||||||
|
|
||||||
- Issue #12713: Allowed abbreviation of subcommands by end-users for users of
|
|
||||||
argparse.
|
|
||||||
|
|
||||||
Tests
|
Tests
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue