Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Click multiple command names

Is it possible to do something like this with Python Click?

@click.command(name=['my-command', 'my-cmd'])
def my_command():
    pass

I want my command lines to be something like:

mycli my-command

and

mycli my-cmd 

but reference the same function.

Do I need to do a class like AliasedGroup?

like image 891
Élie Deloumeau-Prigent Avatar asked Oct 09 '17 08:10

Élie Deloumeau-Prigent


Video Answer


2 Answers

AliasedGroup is not what you are after, since it allows a shortest prefix match, and it appears you need actual aliases. But that example does provide hints in a direction that can work. It inherits from click.Group and overides some behavior.

Here is a one way to approach what you are after:

Custom Class

This class overides the click.Group.command() method which is used to decorate command functions. It adds the ability to pass a list of command aliases. This class also adds a short help which references the aliased command.

class CustomMultiCommand(click.Group):

    def command(self, *args, **kwargs):
        """Behaves the same as `click.Group.command()` except if passed
        a list of names, all after the first will be aliases for the first.
        """
        def decorator(f):
            if isinstance(args[0], list):
                _args = [args[0][0]] + list(args[1:])
                for alias in args[0][1:]:
                    cmd = super(CustomMultiCommand, self).command(
                        alias, *args[1:], **kwargs)(f)
                    cmd.short_help = "Alias for '{}'".format(_args[0])
            else:
                _args = args
            cmd = super(CustomMultiCommand, self).command(
                *_args, **kwargs)(f)
            return cmd

        return decorator

Using the Custom Class

By passing the cls parameter to the click.group() decorator, any commands added to the group via the the group.command() can be passed a list of command names.

@click.group(cls=CustomMultiCommand)
def cli():
    """My Excellent CLI"""

@cli.command(['my-command', 'my-cmd'])
def my_command():
    ....

Test Code:

import click

@click.group(cls=CustomMultiCommand)
def cli():
    """My Excellent CLI"""


@cli.command(['my-command', 'my-cmd'])
def my_command():
    """This is my command"""
    print('Running the command')


if __name__ == '__main__':
    cli('--help'.split())

Test Results:

Usage: my_cli [OPTIONS] COMMAND [ARGS]...

  My Excellent CLI

Options:
  --help  Show this message and exit.

Commands:
  my-cmd      Alias for 'my-command'
  my-command  This is my command
like image 184
Stephen Rauch Avatar answered Sep 17 '22 17:09

Stephen Rauch


Here is a simpler way to solve the same thing:

class AliasedGroup(click.Group):
    def get_command(self, ctx, cmd_name):
        try:
            cmd_name = ALIASES[cmd_name].name
        except KeyError:
            pass
        return super().get_command(ctx, cmd_name)


@click.command(cls=AliasedGroup)
def cli():
    ...

@click.command()
def install():
    ...

@click.command()
def remove():
    ....


cli.add_command(install)
cli.add_command(remove)


ALIASES = {
    "it": install,
    "rm": remove,
}
like image 20
Dev Aggarwal Avatar answered Sep 17 '22 17:09

Dev Aggarwal