延伸点击

除了库本身中实现的常见功能外,还有无数模式可以通过扩展Click来实现。 本页应该深入了解可以实现的目标。

自定义组

您可以通过子类化自定义群组的行为,超出群组接受的参数 click.Group .

最常见的覆盖方法是 get_command()list_commands() .

下面的示例实现了一个基本的插件系统,该系统从文件夹中的Python文件加载命令。该命令是懒惰加载的,以避免启动缓慢。

import importlib.util
import os
import click

class PluginGroup(click.Group):
    def __init__(self, name=None, plugin_folder="commands", **kwargs):
        super().__init__(name=name, **kwargs)
        self.plugin_folder = plugin_folder

    def list_commands(self, ctx):
        rv = []

        for filename in os.listdir(self.plugin_folder):
            if filename.endswith(".py"):
                rv.append(filename[:-3])

        rv.sort()
        return rv

    def get_command(self, ctx, name):
        path = os.path.join(self.plugin_folder, f"{name}.py")
        spec = importlib.util.spec_from_file_location(name, path)
        module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(module)
        return module.cli

cli = PluginGroup(
    plugin_folder=os.path.join(os.path.dirname(__file__), "commands")
)

if __name__ == "__main__":
    cli()

自定义类也可以与装饰器一起使用:

@click.group(
    cls=PluginGroup,
    plugin_folder=os.path.join(os.path.dirname(__file__), "commands")
)
def cli():
    pass

命令别名

许多工具支持命令别名。例如,您可以配置 git 接受 git ci 作为别名 git commit .其他工具还支持通过自动缩短别名来自动发现别名。

可以定制 Group 以提供此功能。解释 自定义组 ,一群提供了两种方法: list_commands()get_command() .在这种特殊情况下,您只需要重写后者,因为您通常不想在帮助页面上列举别名以避免混淆。

下面的示例实现的一个子集 Group 它接受命令的前置。如果有一个命令被称为 push ,它会接受 pus 作为别名(只要它是唯一的):

class AliasedGroup(click.Group):
    def get_command(self, ctx, cmd_name):
        rv = super().get_command(ctx, cmd_name)

        if rv is not None:
            return rv

        matches = [
            x for x in self.list_commands(ctx)
            if x.startswith(cmd_name)
        ]

        if not matches:
            return None

        if len(matches) == 1:
            return click.Group.get_command(self, ctx, matches[0])

        ctx.fail(f"Too many matches: {', '.join(sorted(matches))}")

    def resolve_command(self, ctx, args):
        # always return the full command name
        _, cmd, args = super().resolve_command(ctx, args)
        return cmd.name, cmd, args

它可以这样使用:

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

@cli.command
def push():
    pass

@cli.command
def pop():
    pass

看到 alias example 另一个例子是Click的存储库中。