26

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

我想cmd3拥有与 和 相同的选项和cmd1标志cmd2。就像某种继承。

@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

所以cmd3会有 flag--verbose和 option --directory。是否可以使用 Click 进行此操作?也许我只是忽略了文档中的某些内容...

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

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

4

4 回答 4

34

我找到了一个简单的解决方案!我稍微编辑了来自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()
于 2016-10-22T18:49:37.017 回答
26

定义一个具有公共参数的类

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

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

@click.command(cls=StdCommand)
@click.option('--other')
def main(default_option, other):
  ...
于 2018-12-20T20:24:59.763 回答
3

此代码从其参数中提取所有选项

def extract_params(*args):
    from click import Command
    if len(args) == 0:
        return ['']
    if any([ not isinstance(a, Command) for a in args ]):
        raise TypeError('Handles only Command instances')

    params = [ p.opts() for cmd_inst in args for p in cmd_inst.params ]
    return list(set(params))

现在你可以使用它了:

@click.command()
@click.option(extract_params(cmd1, cmd2))
def cmd3():
    pass

此代码仅提取参数而不提取其默认值,如果需要,您可以对其进行改进。

于 2016-10-21T18:22:39.360 回答
1

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

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)
于 2021-09-07T04:48:41.443 回答