summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Bethard <steven.bethard@gmail.com>2010-12-18 11:19:23 (GMT)
committerSteven Bethard <steven.bethard@gmail.com>2010-12-18 11:19:23 (GMT)
commitfd311a712d5876c3a3efff265978452eea759f85 (patch)
tree6222b825a28cbe2e94f167eb4f1ae519c6dada52
parent04129748ae4f794dffbcf07bf53be27dc79c2d09 (diff)
downloadcpython-fd311a712d5876c3a3efff265978452eea759f85.zip
cpython-fd311a712d5876c3a3efff265978452eea759f85.tar.gz
cpython-fd311a712d5876c3a3efff265978452eea759f85.tar.bz2
Add subparser aliases for argparse. Resolves issue 9324. Approved by Georg for beta2 on the tracker.
-rw-r--r--Doc/library/argparse.rst12
-rw-r--r--Lib/argparse.py17
-rw-r--r--Lib/test/test_argparse.py51
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS2
5 files changed, 77 insertions, 6 deletions
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
index 0ca8aa0..72878c5 100644
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -1428,6 +1428,16 @@ Sub-commands
{foo,bar} additional help
+ Furthermore, ``add_parser`` supports an additional ``aliases`` argument,
+ which allows multiple strings to refer to the same subparser. This example,
+ like ``svn``, aliases ``co`` as a shorthand for ``checkout``::
+
+ >>> parser = argparse.ArgumentParser()
+ >>> subparsers = parser.add_subparsers()
+ >>> checkout = subparsers.add_parser('checkout', aliases=['co'])
+ >>> checkout.add_argument('foo')
+ >>> parser.parse_args(['co', 'bar'])
+ Namespace(foo='bar')
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
@@ -1466,7 +1476,7 @@ Sub-commands
>>> args.func(args)
((XYZYX))
- This way, you can let :meth:`parse_args` does the job of calling the
+ This way, you can let :meth:`parse_args` do the job of calling the
appropriate function after argument parsing is complete. Associating
functions with actions like this is typically the easiest way to handle the
different actions for each of your subparsers. However, if it is necessary
diff --git a/Lib/argparse.py b/Lib/argparse.py
index 557cc00..57eaaad 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1023,9 +1023,13 @@ class _SubParsersAction(Action):
class _ChoicesPseudoAction(Action):
- def __init__(self, name, help):
+ def __init__(self, name, aliases, help):
+ metavar = dest = name
+ if aliases:
+ metavar += ' (%s)' % ', '.join(aliases)
sup = super(_SubParsersAction._ChoicesPseudoAction, self)
- sup.__init__(option_strings=[], dest=name, help=help)
+ sup.__init__(option_strings=[], dest=dest, help=help,
+ metavar=metavar)
def __init__(self,
option_strings,
@@ -1053,15 +1057,22 @@ class _SubParsersAction(Action):
if kwargs.get('prog') is None:
kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
+ aliases = kwargs.pop('aliases', ())
+
# create a pseudo-action to hold the choice help
if 'help' in kwargs:
help = kwargs.pop('help')
- choice_action = self._ChoicesPseudoAction(name, help)
+ choice_action = self._ChoicesPseudoAction(name, aliases, help)
self._choices_actions.append(choice_action)
# create the parser and add it to the map
parser = self._parser_class(**kwargs)
self._name_parser_map[name] = parser
+
+ # make parser available under aliases also
+ for alias in aliases:
+ self._name_parser_map[alias] = parser
+
return parser
def _get_subactions(self):
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 0b7ed5e..d536be9 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -1708,7 +1708,8 @@ class TestAddSubparsers(TestCase):
def assertArgumentParserError(self, *args, **kwargs):
self.assertRaises(ArgumentParserError, *args, **kwargs)
- def _get_parser(self, subparser_help=False, prefix_chars=None):
+ def _get_parser(self, subparser_help=False, prefix_chars=None,
+ aliases=False):
# create a parser with a subparsers argument
if prefix_chars:
parser = ErrorRaisingArgumentParser(
@@ -1724,13 +1725,21 @@ class TestAddSubparsers(TestCase):
'bar', type=float, help='bar help')
# check that only one subparsers argument can be added
- subparsers = parser.add_subparsers(help='command help')
+ subparsers_kwargs = {}
+ if aliases:
+ subparsers_kwargs['metavar'] = 'COMMAND'
+ subparsers_kwargs['title'] = 'commands'
+ else:
+ subparsers_kwargs['help'] = 'command help'
+ subparsers = parser.add_subparsers(**subparsers_kwargs)
self.assertArgumentParserError(parser.add_subparsers)
# add first sub-parser
parser1_kwargs = dict(description='1 description')
if subparser_help:
parser1_kwargs['help'] = '1 help'
+ if aliases:
+ parser1_kwargs['aliases'] = ['1alias1', '1alias2']
parser1 = subparsers.add_parser('1', **parser1_kwargs)
parser1.add_argument('-w', type=int, help='w help')
parser1.add_argument('x', choices='abc', help='x help')
@@ -1947,6 +1956,44 @@ class TestAddSubparsers(TestCase):
-y {1,2,3} y help
'''))
+ def test_alias_invocation(self):
+ parser = self._get_parser(aliases=True)
+ self.assertEqual(
+ parser.parse_known_args('0.5 1alias1 b'.split()),
+ (NS(foo=False, bar=0.5, w=None, x='b'), []),
+ )
+ self.assertEqual(
+ parser.parse_known_args('0.5 1alias2 b'.split()),
+ (NS(foo=False, bar=0.5, w=None, x='b'), []),
+ )
+
+ def test_error_alias_invocation(self):
+ parser = self._get_parser(aliases=True)
+ self.assertArgumentParserError(parser.parse_args,
+ '0.5 1alias3 b'.split())
+
+ def test_alias_help(self):
+ parser = self._get_parser(aliases=True, subparser_help=True)
+ self.maxDiff = None
+ self.assertEqual(parser.format_help(), textwrap.dedent("""\
+ usage: PROG [-h] [--foo] bar COMMAND ...
+
+ main description
+
+ positional arguments:
+ bar bar help
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --foo foo help
+
+ commands:
+ COMMAND
+ 1 (1alias1, 1alias2)
+ 1 help
+ 2 2 help
+ """))
+
# ============
# Groups tests
# ============
diff --git a/Misc/ACKS b/Misc/ACKS
index eaf98a3..1bd0f33 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -734,6 +734,7 @@ Hajime Saitou
George Sakkis
Rich Salz
Kevin Samborn
+Adrian Sampson
Ilya Sandler
Mark Sapiro
Ty Sarna
diff --git a/Misc/NEWS b/Misc/NEWS
index 37a2333..fdda482 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -84,6 +84,8 @@ Build
- The Windows build now uses Tcl/Tk 8.5.9 and sqlite3 3.7.4.
+- Issue #9234: argparse supports alias names for subparsers.
+
What's New in Python 3.2 Beta 1?
================================