Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

@panzi 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

This comment has been minimized.

Copy link
Owner Author

@sampsyo 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

This comment has been minimized.

Copy link

@xiaket 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

This comment has been minimized.

Copy link

@angarg angarg commented Dec 2, 2018

Nice! Thanks for sharing.

@LiamGow

This comment has been minimized.

Copy link

@LiamGow 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

This comment has been minimized.

Copy link

@Helveg Helveg commented Nov 21, 2019

Works very nicely @LiamGow

@studersi

This comment has been minimized.

Copy link

@studersi studersi commented Mar 6, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.