diff -r e97696c583c6 Doc/library/argparse.rst --- a/Doc/library/argparse.rst Mon Dec 13 23:50:30 2010 +0100 +++ b/Doc/library/argparse.rst Fri Dec 17 16:13:27 2010 -0800 @@ -1428,6 +1428,16 @@ {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 @@ >>> 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 -r e97696c583c6 Lib/argparse.py --- a/Lib/argparse.py Mon Dec 13 23:50:30 2010 +0100 +++ b/Lib/argparse.py Fri Dec 17 16:13:27 2010 -0800 @@ -1023,9 +1023,13 @@ 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 @@ 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 -r e97696c583c6 Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Mon Dec 13 23:50:30 2010 +0100 +++ b/Lib/test/test_argparse.py Fri Dec 17 16:13:27 2010 -0800 @@ -1708,7 +1708,8 @@ 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 @@ '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 @@ -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 -r e97696c583c6 Misc/ACKS --- a/Misc/ACKS Mon Dec 13 23:50:30 2010 +0100 +++ b/Misc/ACKS Fri Dec 17 16:13:27 2010 -0800 @@ -731,6 +731,7 @@ George Sakkis Rich Salz Kevin Samborn +Adrian Sampson Ilya Sandler Mark Sapiro Ty Sarna diff -r e97696c583c6 Misc/NEWS --- a/Misc/NEWS Mon Dec 13 23:50:30 2010 +0100 +++ b/Misc/NEWS Fri Dec 17 16:13:27 2010 -0800 @@ -23,6 +23,8 @@ It is now platform specific, keeping its default of False on Windows and changing the default to True on POSIX and other platforms. +- Issue #9234: argparse supports alias names for subparsers. + What's New in Python 3.2 Beta 1? ================================