相当于 sys.argv 的点击

Equivalent of sys.argv in click

我在 Python 中使用 click 为我的程序创建 CLI。如果发生异常,我想执行一个函数(下面通过占位符 do_something() 表示),但前提是某个参数通过 CLI 传递(此处:--verbose-v)。

我知道我可以通过 sys.argv 访问命令行输入。这是我使用这种方法的概念性最小工作示例:

#filename: my_app.py

import click

@click.group()
@click.option('--verbose', '-v', is_flag=True)
def cli():
    pass


@click.command()
def greeting():
    print('hello world')
    raise Exception


@cli.command()
def spam():
    print('SPAM')
    raise Exception


def do_something():
    print('Doing something...')


if __name__ == '__main__':
    try:
        main()
    except e:
        if '--verbose' in sys.argv or '-v' in sys.argv:
            do_something()
        raise e

尽可能准确:如果任何子命令出现异常,我希望程序在 --verbose 标志打开时 do_something(),但如果它不是离开。例如。对于 greeting 子命令,CLI 的行为应如下所示:

~$ python my_app.py --verbose greeting
hello world
Doing something...
Exception
~$ python my_app.py greeting
hello world
Exception

虽然上面显示的 sys.argv 解决方案有效,但如果我可以使用 click 的内部名称(在本例中为 'verbose')引用命令行选项,那就太好了。也就是说,我想在这里做这样的事情:

...
    
if __name__ == '__main__':
    try:
        main()
    except e:
        if 'verbose' in click.argv:
            do_something()
        raise e

这是click提供的功能吗?

如果我错了请纠正我,但在我看来你希望能够在出现异常的情况下输出更多information/clean。

您可以尝试以下几种选择:

  1. 将 try/except 逻辑移动到利用 verbose 标志的 greeting 方法中,并在那里调用 do_something
  2. Consider looking at callbacks 看看你是否可以利用这些来做你想做的事。如果 do_something 没有更多上下文,我无法确定它是否是回调的良好用例。
  3. 最接近您的问题的是拥有一个全局范围变量 _verbose,如下例所示:
import click

global _verbose
_verbose = False


def do_something():
    print(f'Doing something')


@click.group()
def cli():
    pass


@cli.command()
@click.option('--verbose', '-v', is_flag=True)
def greeting():
    global _verbose
    _verbose = verbose
    if verbose:
        print('hello world')
        raise Exception("Test")
    else:
        print('hello')


@cli.command()
@click.option('--count', '-c')
def spam(count):
    print(count * 'SPAM')


if __name__ == '__main__':
    try:
        cli()
    except Exception as e:
        if _verbose:
            do_something()
        raise e

我已经用一个工作片段更新了我的答案,该片段不依赖全局变量来执行此操作,而是利用 Python 的 pass-by-reference 和 click 的高级上下文示例

import click


def do_something():
    print(f'Doing something')


@click.group()
@click.option('--verbose', '-v', is_flag=True)
@click.pass_context
def cli(ctx, verbose):
    ctx.obj['verbose'] = verbose
    pass


@cli.command()
@click.pass_context
def greeting(ctx):
    if ctx.obj['verbose']:
        print('hello world')
        raise Exception("Test")
    else:
        print('hello')


@cli.command()
@click.option('--count', '-c')
def spam(count):
    print(count * 'SPAM')


if __name__ == '__main__':
    flags = {}
    try:
        cli(obj=flags)
    except Exception as e:
        if flags['verbose']:
            do_something()
        raise e