首页 > 解决方案 > Python Click - 如果父命令成功执行,则仅执行子命令

问题描述

我正在使用Click构建 Python CLI,并且遇到了如何在 Click 中处理异常的问题。

我不确定这里的措辞(“subcommand”,“parentcommand”),但从我的例子中你会得到我希望的想法。让我们假设这段代码:

@click.group()
@click.option("--something")
def mycli(something):
    try:
        #do something with "something" and set ctx
        ctx.obj = {}
        ctx.obj["somevar"] = some_result
    except:
        print("Something went wrong")
        raise

    #only if everything went fine call mycommand

@click.group()
@click.pass_context
def mygroup(ctx):
    pass

@mygroup.command(name="mycommand")
@click.pass_context
def mycommand(ctx):
    #this only works if somevar is set in ctx so don't call this if setting went wrong in mycli

当应用程序启动时,它被调用:

if __name__ == "__main__":
    mycli.add_command(mygroup)
    mycli()

然后我像这样启动程序:

python myapp --something somevalue mycommand

预期行为:首先mycli调用并执行其中的代码。如果抛出异常,它会被 except 块捕获,会打印一条消息并引发异常。因为我们没有其他 try/except 块,这将导致脚本终止。“sub”-commandmycommand永远不会被调用,因为程序在运行“parent”-command 时已经终止mycli

实际行为:异常被捕获并打印消息,但mycommand仍被调用。然后它失败并显示另一个异常消息,因为未设置所需的上下文变量。

我将如何处理这样的事情?基本上我只想在mycommand一切正常的情况下调用子命令才能执行mycli

标签: pythonpython-click

解决方案


要处理异常,但不继续执行子命令,您可以简单地调用exit()如下:

代码:

import click

@click.group()
@click.option("--something")
@click.pass_context
def mycli(ctx, something):
    ctx.obj = dict(a_var=something)
    try:
        if something != '1':
            raise IndexError('An Error')
    except Exception as exc:
        click.echo('Exception: {}'.format(exc))
        exit()

测试代码:

@mycli.group()
@click.pass_context
def mygroup(ctx):
    click.echo('mygroup: {}'.format(ctx.obj['a_var']))
    pass


@mygroup.command()
@click.pass_context
def mycommand(ctx):
    click.echo('mycommand: {}'.format(ctx.obj['a_var']))


if __name__ == "__main__":
    commands = (
        'mygroup mycommand',
        '--something 1 mygroup mycommand',
        '--something 2 mygroup mycommand',
        '--help',
        '--something 1 mygroup --help',
        '--something 1 mygroup mycommand --help',
    )

    import sys, time

    time.sleep(1)
    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    for cmd in commands:
        try:
            time.sleep(0.1)
            print('-----------')
            print('> ' + cmd)
            time.sleep(0.1)
            mycli(cmd.split())

        except BaseException as exc:
            if str(exc) != '0' and \
                    not isinstance(exc, (click.ClickException, SystemExit)):
                raise

结果:

Click Version: 6.7
Python Version: 3.6.3 (v3.6.3:2c5fed8, Oct  3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)]
-----------
> mygroup mycommand
Exception: An Error
-----------
> --something 1 mygroup mycommand
mygroup: 1
mycommand: 1
-----------
> --something 2 mygroup mycommand
Exception: An Error
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

Options:
  --something TEXT
  --help            Show this message and exit.

Commands:
  mygroup
-----------
> --something 1 mygroup --help
Usage: test.py mygroup [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  mycommand
-----------
> --something 1 mygroup mycommand --help
mygroup: 1
Usage: test.py mygroup mycommand [OPTIONS]

Options:
  --help  Show this message and exit.

推荐阅读