Skip to content

Instantly share code, notes, and snippets.

@sampsyo
Created July 11, 2010 20:04
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save sampsyo/471779 to your computer and use it in GitHub Desktop.
Save sampsyo/471779 to your computer and use it in GitHub Desktop.
hack for argparse adding subcommand aliases
#!/usr/bin/env python
"""Aliases for argparse positional arguments."""
import argparse
class AliasedSubParsersAction(argparse._SubParsersAction):
class _AliasedPseudoAction(argparse.Action):
def __init__(self, name, aliases, help):
dest = name
if aliases:
dest += ' (%s)' % ','.join(aliases)
sup = super(AliasedSubParsersAction._AliasedPseudoAction, self)
sup.__init__(option_strings=[], dest=dest, help=help)
def add_parser(self, name, **kwargs):
if 'aliases' in kwargs:
aliases = kwargs['aliases']
del kwargs['aliases']
else:
aliases = []
parser = super(AliasedSubParsersAction, self).add_parser(name, **kwargs)
# Make the aliases work.
for alias in aliases:
self._name_parser_map[alias] = parser
# Make the help text reflect them, first removing old help entry.
if 'help' in kwargs:
help = kwargs.pop('help')
self._choices_actions.pop()
pseudo_action = self._AliasedPseudoAction(name, aliases, help)
self._choices_actions.append(pseudo_action)
return parser
if __name__ == '__main__':
# An example parser with subcommands.
parser = argparse.ArgumentParser()
parser.register('action', 'parsers', AliasedSubParsersAction)
parser.add_argument("--library", metavar="libfile", type=str,
help="library database filename")
subparsers = parser.add_subparsers(title="commands", metavar="COMMAND")
p_import = subparsers.add_parser("import", help="add files to library",
aliases=('imp', 'im'))
p_import.add_argument("filename", metavar="file", type=str, nargs="+",
help="the files to import")
p_remove = subparsers.add_parser("remove", aliases=('rm',),
help="remove items")
args = parser.parse_args()
print args
@panzi
Copy link

panzi commented Jun 15, 2014

Thanks for that! What license is this code? Can I use it in GPL or BSD code? How do I have to credit you?

@sampsyo
Copy link
Author

sampsyo commented Jun 28, 2016

Since I've gotten this question a few times: I dedicate this code to the public domain. You can use it freely for any purpose.

@xiaket
Copy link

xiaket commented Jun 12, 2018

Thanks for the snippet!

        if 'aliases' in kwargs:
            aliases = kwargs['aliases']
            del kwargs['aliases']
        else:
            aliases = []

could simply be:

aliases = kwargs.pop('aliases', [])

@angarg
Copy link

angarg commented Dec 2, 2018

Nice! Thanks for sharing.

@LiamGow
Copy link

LiamGow commented Apr 11, 2019

If I might add an updated version, the following includes xiaket's modification, and also overrides the default parsers action so you don't have to register it per parser.

I don't know much about python importing practices - this may be a horrible idea, but it works for me regardless of whether this file or argparse is imported first in another file, and works for recursive subparsers, so if you're lazy like me, maybe give it a try.

class AliasedSubParsersAction(argparse._SubParsersAction):
    old_init = staticmethod(argparse._ActionsContainer.__init__)

    @staticmethod
    def _containerInit(self, description, prefix_chars, argument_default, conflict_handler):
        AliasedSubParsersAction.old_init(self, description, prefix_chars, argument_default, conflict_handler)
        self.register('action', 'parsers', AliasedSubParsersAction)

    class _AliasedPseudoAction(argparse.Action):
        def __init__(self, name, aliases, help):
            dest = name
            if aliases:
                dest += ' (%s)' % ','.join(aliases)
            sup = super(AliasedSubParsersAction._AliasedPseudoAction, self)
            sup.__init__(option_strings=[], dest=dest, help=help)

    def add_parser(self, name, **kwargs):
        aliases = kwargs.pop('aliases', [])
        parser = super(AliasedSubParsersAction, self).add_parser(name, **kwargs)

        # Make the aliases work.
        for alias in aliases:
            self._name_parser_map[alias] = parser
        # Make the help text reflect them, first removing old help entry.
        if 'help' in kwargs:
            help = kwargs.pop('help')
            self._choices_actions.pop()
            pseudo_action = self._AliasedPseudoAction(name, aliases, help)
            self._choices_actions.append(pseudo_action)

        return parser


# override argparse to register new subparser action by default
argparse._ActionsContainer.__init__ = AliasedSubParsersAction._containerInit

@Helveg
Copy link

Helveg commented Nov 21, 2019

Works very nicely @LiamGow

@studersi
Copy link

studersi commented Mar 6, 2020

@sampsyo Thank you so much! This is just what I needed :-)

@panzi
Copy link

panzi commented Nov 15, 2020

Python now supports this built-in. Does anyone know in which exact version it was added to Python?
(And again, thank you for this gist.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment