我可以有一个调用所有其他子命令的 main() Click 函数吗?
Can I have a main() Click function that invokes all other sub-commands?
我有一个像这样的脚本:
#myscript.py
import click
def step1(arg1):
print('Step 1: ' + arg1)
def step2(arg2):
print('Step 2: ' + arg2)
def main(arg1, arg2):
step1(arg1)
step2(arg2)
大多数时候我想运行脚本用myscript arg1 arg2
,但偶尔我可能想运行只有一步:例如myscript step1 arg1
。 我如何设置点击执行此操作? 有没有一种方法可以有一个默认命令,然后有其他可选命令?
这似乎是一件事 Click discourages:
Sometimes, it might be interesting to invoke one command from another command. This is a pattern that is generally discouraged with Click, but possible nonetheless.
我需要使用这个 click.invoke()
模式吗?
我认为 Multi Command Chaining and Multi Command Pipelines 功能旨在涵盖这种情况。流水线提供了所请求的确切行为(当命令行上没有给出任何内容时调用 step1
和 step2
),但它更冗长,并且带有 chain=True
none 参数可以是可选的;您必须 (a) 始终同时提供 arg1
和 arg2
,即使仅调用 step2
;或 (b) 将这些参数转换为选项(--arg1 foo
而不是 foo
)。
链接
import click
@click.group(chain=True)
def cli():
pass
@cli.command()
@click.argument('arg1')
def step1(arg1):
click.echo('Step 1: ' + arg1)
@cli.command()
@click.argument('arg2')
def step2(arg2):
click.echo('Step 2: ' + arg2)
cli()
然后:
$ python3 chain.py step1 foo step2 bar
Step 1: foo
Step 2: bar
$ python3 chain.py step2 bar
Step 2: bar
流水线
import click
@click.group(chain=True, invoke_without_command=True)
@click.argument('arg1')
@click.argument('arg2')
def cli(arg1, arg2):
pass
@cli.resultcallback()
def process_pipeline(processors, **kwargs):
# If no commands given, invoke step1 then step2
processors = processors if len(processors) else [step1, step2]
for processor in processors:
processor(**kwargs)
def step1(**kwargs):
click.echo('Step 1: ' + kwargs['arg1'])
def step2(**kwargs):
click.echo('Step 2: ' + kwargs['arg2'])
@cli.command('step1')
def make_step1():
return step1
@cli.command('step2')
def make_step2():
return step2
cli()
然后
$ python3 pipeline.py foo bar
Step 1: foo
Step 2: bar
$ python3 pipeline.py foo bar step2
Step 2: bar
我没有对问题进行措辞来完全解释我正在尝试做什么,因为每个步骤还需要前一个步骤的输出。非常感谢 让我走上了正确的道路。
我的解决方案是这样的:
@click.group(invoke_without_command=True)
@click.option('--arg1')
@click.option('--arg2')
@click.pass_context
def cli(ctx, arg1, arg2):
'''Description
'''
if ctx.invoked_subcommand is None:
do_everything(ctx, arg1, arg2)
@cli.command()
@click.option('--arg1')
def step_1(arg1):
return do_something(arg1)
@cli.command()
@click.argument('step_one_result')
@click.option('--arg2')
def step_2(step_one_result, arg2):
do_something_else(step_one_result, arg2)
def do_everything(ctx, arg1, arg2):
step_one_result = ctx.invoke(step_1, arg1=arg1)
ctx.invoke(do_something_else, step_one_result=step_one_result, arg2=arg2)
#and because of weirdness with pass_context and using setuptools
def main():
cli(obj={})
if __name__ == '__main__':
main()
编辑: 您会注意到使用了 ctx.invoke()
,这是调用函数所必需的,不会出现以下错误
line 619, in make_context
ctx = Context(self, info_name=info_name, parent=parent, **extra)
TypeError: __init__() got an unexpected keyword argument 'arg1'
我有一个像这样的脚本:
#myscript.py
import click
def step1(arg1):
print('Step 1: ' + arg1)
def step2(arg2):
print('Step 2: ' + arg2)
def main(arg1, arg2):
step1(arg1)
step2(arg2)
大多数时候我想运行脚本用myscript arg1 arg2
,但偶尔我可能想运行只有一步:例如myscript step1 arg1
。 我如何设置点击执行此操作? 有没有一种方法可以有一个默认命令,然后有其他可选命令?
这似乎是一件事 Click discourages:
Sometimes, it might be interesting to invoke one command from another command. This is a pattern that is generally discouraged with Click, but possible nonetheless.
我需要使用这个 click.invoke()
模式吗?
我认为 Multi Command Chaining and Multi Command Pipelines 功能旨在涵盖这种情况。流水线提供了所请求的确切行为(当命令行上没有给出任何内容时调用 step1
和 step2
),但它更冗长,并且带有 chain=True
none 参数可以是可选的;您必须 (a) 始终同时提供 arg1
和 arg2
,即使仅调用 step2
;或 (b) 将这些参数转换为选项(--arg1 foo
而不是 foo
)。
链接
import click
@click.group(chain=True)
def cli():
pass
@cli.command()
@click.argument('arg1')
def step1(arg1):
click.echo('Step 1: ' + arg1)
@cli.command()
@click.argument('arg2')
def step2(arg2):
click.echo('Step 2: ' + arg2)
cli()
然后:
$ python3 chain.py step1 foo step2 bar
Step 1: foo
Step 2: bar
$ python3 chain.py step2 bar
Step 2: bar
流水线
import click
@click.group(chain=True, invoke_without_command=True)
@click.argument('arg1')
@click.argument('arg2')
def cli(arg1, arg2):
pass
@cli.resultcallback()
def process_pipeline(processors, **kwargs):
# If no commands given, invoke step1 then step2
processors = processors if len(processors) else [step1, step2]
for processor in processors:
processor(**kwargs)
def step1(**kwargs):
click.echo('Step 1: ' + kwargs['arg1'])
def step2(**kwargs):
click.echo('Step 2: ' + kwargs['arg2'])
@cli.command('step1')
def make_step1():
return step1
@cli.command('step2')
def make_step2():
return step2
cli()
然后
$ python3 pipeline.py foo bar
Step 1: foo
Step 2: bar
$ python3 pipeline.py foo bar step2
Step 2: bar
我没有对问题进行措辞来完全解释我正在尝试做什么,因为每个步骤还需要前一个步骤的输出。非常感谢
我的解决方案是这样的:
@click.group(invoke_without_command=True)
@click.option('--arg1')
@click.option('--arg2')
@click.pass_context
def cli(ctx, arg1, arg2):
'''Description
'''
if ctx.invoked_subcommand is None:
do_everything(ctx, arg1, arg2)
@cli.command()
@click.option('--arg1')
def step_1(arg1):
return do_something(arg1)
@cli.command()
@click.argument('step_one_result')
@click.option('--arg2')
def step_2(step_one_result, arg2):
do_something_else(step_one_result, arg2)
def do_everything(ctx, arg1, arg2):
step_one_result = ctx.invoke(step_1, arg1=arg1)
ctx.invoke(do_something_else, step_one_result=step_one_result, arg2=arg2)
#and because of weirdness with pass_context and using setuptools
def main():
cli(obj={})
if __name__ == '__main__':
main()
编辑: 您会注意到使用了 ctx.invoke()
,这是调用函数所必需的,不会出现以下错误
line 619, in make_context
ctx = Context(self, info_name=info_name, parent=parent, **extra)
TypeError: __init__() got an unexpected keyword argument 'arg1'