One way to provide some aliases is to intercept the command and directly manipulate the args list. This can be done using a special class, for example:
Custom class
This class overrides the click.Group.__call__() method, which allows you to edit the args list before invoking the shell. He also overrides format_epilog to add reference documentation for aliases.
class ExpandAliasesGroup(click.Group): def __init__(self, *args, **kwargs): self.aliases = kwargs.pop('aliases', {}) super(ExpandAliasesGroup, self).__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if args[0][0] in self.aliases: alias = self.aliases[args[0][0]] args[0].pop(0) for command in reversed(alias): args[0].insert(0, command) return super(ExpandAliasesGroup, self).__call__(*args, **kwargs) @property def alias_help(self): return '\n'.join( '{}: {}'.format(alias, ' '.join(commands)) for alias, commands in sorted(self.aliases.items()) ) def format_epilog(self, ctx, formatter): """Inject our aliases into the help string""" if self.aliases: formatter.write_paragraph() formatter.write_text('Aliases:') with formatter.indentation(): formatter.write_text(self.alias_help)
Using a custom class
By click.group() cls parameter and an alias pointer to the click.group() decorator, the click.group() class can perform the alias extension.
aliases = dict(all='command1 command2 command3'.split()) @click.group(chain=True, cls=ExpandAliasesGroup, aliases=aliases) def cli(): ....
How it works?
This works because a click is a well-designed OO framework. The @click.group() decorator usually creates an instance of the click.Group object, but allows this behavior to exceed the cls parameter. Thus, it is relatively easy to inherit from click.Group in our own class and overcome the necessary methods.
__call__ method, we can intercept all command calls. Then, if the argument list starts with a known alias, we edit the args list by removing this aliased command and replacing it with aliases.
format_epilog method, we can add reference documentation for aliases.
Security Code:
import click aliases = dict(all='command1 command2 command3'.split()) @click.group(cls=ExpandAliasesGroup, chain=True, aliases=aliases) def cli(): pass @cli.command() def command1(): click.echo('Command 1') @cli.command() def command2(): click.echo('Command 2') @cli.command() def command3(): click.echo('Command 3') if __name__ == "__main__": commands = ( 'command1', 'command3', 'command1 command2', 'all', '--help', ) for cmd in commands: try: print('-----------') print('> ' + cmd) cli(cmd.split()) except: pass
Test results:
----------- > command1 Command 1 ----------- > command3 Command 3 ----------- > command1 command2 Command 1 Command 2 ----------- > all Command 1 Command 2 Command 3 ----------- > --help Usage: test.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]... Options: --help Show this message and exit. Commands: command1 Command #1 comes first command2 Command #2 is after command #1 command3 Command #3 saves the best for last Aliases: all: command1 command2 command3