Python 单击多个命令名称

问题描述 投票:0回答:4

可以用 Python Click 做这样的事情吗?

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

我希望我的命令行是这样的:

mycli my-command

mycli my-cmd 

但引用相同的函数。

我需要上像AliasedGroup这样的课程吗?

python command alias python-click
4个回答
13
投票

AliasedGroup 不是您想要的,因为它允许最短的前缀匹配,而且您似乎需要实际的别名。但这个例子确实提供了可行的方向的提示。它继承自

click.Group
并覆盖了一些行为。

这是实现您所追求的目标的一种方法:

自定义类

该类覆盖了用于装饰命令函数的

click.Group.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

使用自定义类

通过将

cls
参数传递给
click.group()
装饰器,通过
group.command()
添加到组的任何命令都可以传递命令名称列表。

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

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

测试代码:

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())

测试结果:

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

10
投票

这里有一个更简单的方法来解决同样的问题:

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,
}

3
投票

自从提出这个问题以来,有人(不是我)创建了一个

click-aliases

它的工作方式有点像其他答案,只是你不必自己声明命令类:

import click
from click_aliases import ClickAliasedGroup

@click.group(cls=ClickAliasedGroup)
def cli():
    pass

@cli.command(aliases=['my-cmd'])
def my_command():
    pass

1
投票

我尝试了@Stephan Rauch 的解决方案,并遇到了一些挑战,例如帮助文本输出,因此我对其进行了扩展。这是在我看到有一个用于此目的的库之前,所以我还没有尝试过,因为我构建的内容正在按照我想要的方式工作。

从基本命令复制帮助信息时向命令添加

aliases=['foo', 'bar']
参数。

班级:

class CustomCliGroup(click.Group):
    """Custom Cli Group for Click"""

    def command(self, *args, **kwargs):
        """Adds the ability to add `aliases` to commands."""

        def decorator(f):
            aliases = kwargs.pop("aliases", None)
            if aliases and isinstance(aliases, list):
                name = kwargs.pop("name", None)
                if not name:
                    raise click.UsageError("`name` command argument is required when using aliases.")

                base_command = super(CustomCliGroup, self).command(
                    name, *args, **kwargs
                )(f)

                for alias in aliases:
                    cmd = super(CustomCliGroup, self).command(alias, *args, **kwargs)(f)
                    cmd.help = f"Alias for '{name}'.\n\n{cmd.help}"
                    cmd.params = base_command.params

            else:
                cmd = super(CustomCliGroup, self).command(*args, **kwargs)(f)

            return cmd

        return decorator

用途:

import click


@click.group(
    context_settings=dict(help_option_names=["-h", "--help"]), cls=CustomCliGroup
)
def cli():
    """My Excellent CLI"""

@cli.command()
def hello():
    """Says hello"""
    click.echo("Hello, World!")

@cli.command(name="do", aliases=["stuff"])
@click.argument("name")
@click.option("--times", "-t", default=1, help="Number of times to do the thing")
def my_command(name, times):
    """This is my command"""
    click.echo(f"Doing {name} {times} times.")


if __name__ == "__main__":
    cli()

输出:

> python test.py -h                                                                                                                          
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  My Excellent CLI

Options:
  -h, --help  Show this message and exit.

Commands:
  do     This is my command
  hello  Says hello
  stuff  Alias for 'do'.

------------------------
> python test.py do -h                                                                                                                        
Usage: test.py do [OPTIONS] NAME

  This is my command

Options:
  -t, --times INTEGER  Number of times to do the thing
  -h, --help           Show this message and exit.

------------------------
> python test.py stuff -h                                                                                                                     
Usage: test.py stuff [OPTIONS] NAME

  Alias for 'do'.

  This is my command

Options:
  -t, --times INTEGER  Number of times to do the thing
  -h, --help           Show this message and exit.
© www.soinside.com 2019 - 2024. All rights reserved.