Python/Click - 命令之间的共享选项和标志

jir*_*ovo 8 python command-line-interface python-click

说我的CLI实用程序有三个命令:cmd1,cmd2,cmd3

我想cmd3有相同的选项和标志为cmd1cmd2.像某种继承.

@click.command()
@click.options("--verbose")
def cmd1():
    pass

@click.command()
@click.options("--directory")
def cmd2():
    pass

@click.command()
@click.inherit(cmd1, cmd2) # HYPOTHETICAL
def cmd3():
    pass
Run Code Online (Sandbox Code Playgroud)

所以cmd3会有标志--verbose和选项--directory.可以用Click做到这一点吗?也许我只是忽略了文档中的内容......

编辑:我知道我可以这样做click.group().但是,必须在组命令之前指定所有组的选项.我想在命令之后通常拥有所有选项.

cli.py --verbose --directory /tmp cmd3 - > cli.py cmd3 --verbose --directory /tmp

小智 21

定义具有公共参数的类

class StdCommand(click.core.Command):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.params.insert(0, click.core.Option(('--default-option',), help='Every command should have one'))
Run Code Online (Sandbox Code Playgroud)

然后在定义命令函数时将类传递给装饰器

@click.command(cls=StdCommand)
@click.option('--other')
def main(default_option, other):
  ...
Run Code Online (Sandbox Code Playgroud)

  • 这是最干净、最优雅的解决方案。工作顺利。我建议将“click.core.Command”替换为“click.Command”。真的不需要去较低的模块。另外,说“self.params = [...]”比插入到空列表更干净。 (2认同)
  • @d0m1n0 第一条评论绝对正确,但第二条评论则不然。该列表不一定是空的,您可以使用建议的方法覆盖其中的内容。当您添加更多选项(“--other”)时,它们就消失了。 (2认同)

jir*_*ovo 13

我找到了简单的解决方案!我稍微编辑了https://github.com/pallets/click/issues/108的片段:

import click


_cmd1_options = [
    click.option('--cmd1-opt')
]

_cmd2_options = [
    click.option('--cmd2-opt')
]


def add_options(options):
    def _add_options(func):
        for option in reversed(options):
            func = option(func)
        return func
    return _add_options


@click.group()
def group(**kwargs):
    pass


@group.command()
@add_options(_cmd1_options)
def cmd1(**kwargs):
    print(kwargs)


@group.command()
@add_options(_cmd2_options)
def cmd2(**kwargs):
    print(kwargs)


@group.command()
@add_options(_cmd1_options)
@add_options(_cmd2_options)
@click.option("--cmd3-opt")
def cmd3(**kwargs):
    print(kwargs)


if __name__ == '__main__':
    group()
Run Code Online (Sandbox Code Playgroud)


Yas*_*thi 11

您还可以使用另一个装饰器来共享选项。我在这里找到了这个解决方案

def common_params(func):
    @click.option('--foo')
    @click.option('--bar')
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper


@click.command()
@common_params
@click.option('--baz')
def cli(foo, bar, baz):
    print(foo, bar, baz)
Run Code Online (Sandbox Code Playgroud)