[Python-checkins] r87362 - in python/branches/py3k: Doc/library/argparse.rst Lib/argparse.py Lib/test/test_argparse.py Misc/ACKS Misc/NEWS

steven.bethard python-checkins at python.org
Sat Dec 18 12:19:23 CET 2010


Author: steven.bethard
Date: Sat Dec 18 12:19:23 2010
New Revision: 87362

Log:
Add subparser aliases for argparse. Resolves issue 9324. Approved by Georg for beta2 on the tracker.

Modified:
   python/branches/py3k/Doc/library/argparse.rst
   python/branches/py3k/Lib/argparse.py
   python/branches/py3k/Lib/test/test_argparse.py
   python/branches/py3k/Misc/ACKS
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/argparse.rst
==============================================================================
--- python/branches/py3k/Doc/library/argparse.rst	(original)
+++ python/branches/py3k/Doc/library/argparse.rst	Sat Dec 18 12:19:23 2010
@@ -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

Modified: python/branches/py3k/Lib/argparse.py
==============================================================================
--- python/branches/py3k/Lib/argparse.py	(original)
+++ python/branches/py3k/Lib/argparse.py	Sat Dec 18 12:19:23 2010
@@ -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):

Modified: python/branches/py3k/Lib/test/test_argparse.py
==============================================================================
--- python/branches/py3k/Lib/test/test_argparse.py	(original)
+++ python/branches/py3k/Lib/test/test_argparse.py	Sat Dec 18 12:19:23 2010
@@ -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
 # ============

Modified: python/branches/py3k/Misc/ACKS
==============================================================================
--- python/branches/py3k/Misc/ACKS	(original)
+++ python/branches/py3k/Misc/ACKS	Sat Dec 18 12:19:23 2010
@@ -734,6 +734,7 @@
 George Sakkis
 Rich Salz
 Kevin Samborn
+Adrian Sampson
 Ilya Sandler
 Mark Sapiro
 Ty Sarna

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Sat Dec 18 12:19:23 2010
@@ -84,6 +84,8 @@
 
 - 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?
 ================================


More information about the Python-checkins mailing list