簡體   English   中英

我可以有一個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不鼓勵一件事

有時,從另一個命令調用一個命令可能很有趣。 單擊通常不建議使用這種模式,但是還是可以的。

我需要使用這種click.invoke()模式嗎?

我認為多命令鏈接多命令管道功能旨在解決這種情況。 流水線提供了所請求的確切行為(在命令行中未給出任何命令時,都會調用step1step2 ),但是它更加冗長,並且使用chain=True任何參數都不是可選的。 您必須(a)始終同時給出arg1arg2 ,即使僅調用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

我沒有用這個問題來表達我要嘗試做的事情,因為每一步都需要前一步的輸出。 非常感謝Paul帶領我走上正確的道路。

我的解決方案是這樣的:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM