使用CLI库click
我有一个带有两个子命令app.py
和read
的应用程序脚本write
:
@click.group()
@click.pass_context
def cli(ctx):
pass
@cli.command()
@click.pass_context
def read(ctx):
print("read")
@cli.command()
@click.pass_context
def write(ctx):
print("write")
我想宣布一个共同的选项--format
。我知道我可以将它作为选项添加到命令组中
@click.group()
@click.option('--format', default='json')
@click.pass_context
def cli(ctx, format):
ctx.obj['format'] = format
但是后来我不能在命令之后给出选项,在我的用例中更加自然。我希望能够在shell中发布:
app.py read --format XXX
但随着概述设置,我得到消息Error: no such option: --format
。该脚本仅接受命令之前的选项。
所以我的问题是:如何为两个子命令添加一个公共选项,以便它像每个子命令的选项一样工作?
AFAICT,Click不可能实现。文档指出:
单击严格分隔命令和子命令之间的参数。这意味着必须在命令名称之后但在任何其他命令名称之前指定特定命令的选项和参数。
一个可能的解决方法是编写一个common_options
装饰器。以下示例使用的事实是click.option
是一个函数,它返回一个期望串行应用的装饰器函数。 IOW,以下内容:
@click.option("-a")
@click.option("-b")
def hello(a, b):
pass
相当于以下内容:
def hello(a, b):
pass
hello = click.option("-a")(click.option("-b")(hello))
缺点是您需要在所有子命令上设置公共参数。这可以通过**kwargs
来解决,import click
import functools
@click.group()
def cli():
pass
def common_options(f):
options = [
click.option("-a", is_flag=True),
click.option("-b", is_flag=True),
]
return functools.reduce(lambda x, opt: opt(x), options, f)
@cli.command()
@common_options
def hello(**kwargs):
print(kwargs)
# to get the value of b:
print(kwargs["b"])
@cli.command()
@common_options
@click.option("-c", "--citrus")
def world(citrus, a, **kwargs):
print("citrus is", citrus)
if a:
print(kwargs)
else:
print("a was not passed")
if __name__ == "__main__":
cli()
将关键字参数收集为dict。
(或者,您可以编写一个更高级的装饰器,将参数提供给上下文或类似的东西,但我的简单尝试不起作用,我还没准备好尝试更高级的方法。我可能会稍后编辑答案,添加它们。)
有了它,我们可以制作一个程序:
qazxswpoi