Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fd311a7

Browse files
committed
Add subparser aliases for argparse. Resolves issue 9324. Approved by Georg for beta2 on the tracker.
1 parent 0412974 commit fd311a7

5 files changed

Lines changed: 77 additions & 6 deletions

File tree

Doc/library/argparse.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,16 @@ Sub-commands
14281428

14291429
{foo,bar} additional help
14301430

1431+
Furthermore, ``add_parser`` supports an additional ``aliases`` argument,
1432+
which allows multiple strings to refer to the same subparser. This example,
1433+
like ``svn``, aliases ``co`` as a shorthand for ``checkout``::
1434+
1435+
>>> parser = argparse.ArgumentParser()
1436+
>>> subparsers = parser.add_subparsers()
1437+
>>> checkout = subparsers.add_parser('checkout', aliases=['co'])
1438+
>>> checkout.add_argument('foo')
1439+
>>> parser.parse_args(['co', 'bar'])
1440+
Namespace(foo='bar')
14311441

14321442
One particularly effective way of handling sub-commands is to combine the use
14331443
of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
@@ -1466,7 +1476,7 @@ Sub-commands
14661476
>>> args.func(args)
14671477
((XYZYX))
14681478

1469-
This way, you can let :meth:`parse_args` does the job of calling the
1479+
This way, you can let :meth:`parse_args` do the job of calling the
14701480
appropriate function after argument parsing is complete. Associating
14711481
functions with actions like this is typically the easiest way to handle the
14721482
different actions for each of your subparsers. However, if it is necessary

Lib/argparse.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,9 +1023,13 @@ class _SubParsersAction(Action):
10231023

10241024
class _ChoicesPseudoAction(Action):
10251025

1026-
def __init__(self, name, help):
1026+
def __init__(self, name, aliases, help):
1027+
metavar = dest = name
1028+
if aliases:
1029+
metavar += ' (%s)' % ', '.join(aliases)
10271030
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
1028-
sup.__init__(option_strings=[], dest=name, help=help)
1031+
sup.__init__(option_strings=[], dest=dest, help=help,
1032+
metavar=metavar)
10291033

10301034
def __init__(self,
10311035
option_strings,
@@ -1053,15 +1057,22 @@ def add_parser(self, name, **kwargs):
10531057
if kwargs.get('prog') is None:
10541058
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
10551059

1060+
aliases = kwargs.pop('aliases', ())
1061+
10561062
# create a pseudo-action to hold the choice help
10571063
if 'help' in kwargs:
10581064
help = kwargs.pop('help')
1059-
choice_action = self._ChoicesPseudoAction(name, help)
1065+
choice_action = self._ChoicesPseudoAction(name, aliases, help)
10601066
self._choices_actions.append(choice_action)
10611067

10621068
# create the parser and add it to the map
10631069
parser = self._parser_class(**kwargs)
10641070
self._name_parser_map[name] = parser
1071+
1072+
# make parser available under aliases also
1073+
for alias in aliases:
1074+
self._name_parser_map[alias] = parser
1075+
10651076
return parser
10661077

10671078
def _get_subactions(self):

Lib/test/test_argparse.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,8 @@ class TestAddSubparsers(TestCase):
17081708
def assertArgumentParserError(self, *args, **kwargs):
17091709
self.assertRaises(ArgumentParserError, *args, **kwargs)
17101710

1711-
def _get_parser(self, subparser_help=False, prefix_chars=None):
1711+
def _get_parser(self, subparser_help=False, prefix_chars=None,
1712+
aliases=False):
17121713
# create a parser with a subparsers argument
17131714
if prefix_chars:
17141715
parser = ErrorRaisingArgumentParser(
@@ -1724,13 +1725,21 @@ def _get_parser(self, subparser_help=False, prefix_chars=None):
17241725
'bar', type=float, help='bar help')
17251726

17261727
# check that only one subparsers argument can be added
1727-
subparsers = parser.add_subparsers(help='command help')
1728+
subparsers_kwargs = {}
1729+
if aliases:
1730+
subparsers_kwargs['metavar'] = 'COMMAND'
1731+
subparsers_kwargs['title'] = 'commands'
1732+
else:
1733+
subparsers_kwargs['help'] = 'command help'
1734+
subparsers = parser.add_subparsers(**subparsers_kwargs)
17281735
self.assertArgumentParserError(parser.add_subparsers)
17291736

17301737
# add first sub-parser
17311738
parser1_kwargs = dict(description='1 description')
17321739
if subparser_help:
17331740
parser1_kwargs['help'] = '1 help'
1741+
if aliases:
1742+
parser1_kwargs['aliases'] = ['1alias1', '1alias2']
17341743
parser1 = subparsers.add_parser('1', **parser1_kwargs)
17351744
parser1.add_argument('-w', type=int, help='w help')
17361745
parser1.add_argument('x', choices='abc', help='x help')
@@ -1947,6 +1956,44 @@ def test_subparser2_help(self):
19471956
-y {1,2,3} y help
19481957
'''))
19491958

1959+
def test_alias_invocation(self):
1960+
parser = self._get_parser(aliases=True)
1961+
self.assertEqual(
1962+
parser.parse_known_args('0.5 1alias1 b'.split()),
1963+
(NS(foo=False, bar=0.5, w=None, x='b'), []),
1964+
)
1965+
self.assertEqual(
1966+
parser.parse_known_args('0.5 1alias2 b'.split()),
1967+
(NS(foo=False, bar=0.5, w=None, x='b'), []),
1968+
)
1969+
1970+
def test_error_alias_invocation(self):
1971+
parser = self._get_parser(aliases=True)
1972+
self.assertArgumentParserError(parser.parse_args,
1973+
'0.5 1alias3 b'.split())
1974+
1975+
def test_alias_help(self):
1976+
parser = self._get_parser(aliases=True, subparser_help=True)
1977+
self.maxDiff = None
1978+
self.assertEqual(parser.format_help(), textwrap.dedent("""\
1979+
usage: PROG [-h] [--foo] bar COMMAND ...
1980+
1981+
main description
1982+
1983+
positional arguments:
1984+
bar bar help
1985+
1986+
optional arguments:
1987+
-h, --help show this help message and exit
1988+
--foo foo help
1989+
1990+
commands:
1991+
COMMAND
1992+
1 (1alias1, 1alias2)
1993+
1 help
1994+
2 2 help
1995+
"""))
1996+
19501997
# ============
19511998
# Groups tests
19521999
# ============

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ Hajime Saitou
734734
George Sakkis
735735
Rich Salz
736736
Kevin Samborn
737+
Adrian Sampson
737738
Ilya Sandler
738739
Mark Sapiro
739740
Ty Sarna

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ Build
8484

8585
- The Windows build now uses Tcl/Tk 8.5.9 and sqlite3 3.7.4.
8686

87+
- Issue #9234: argparse supports alias names for subparsers.
88+
8789

8890
What's New in Python 3.2 Beta 1?
8991
================================

0 commit comments

Comments
 (0)