繁体   English   中英

如何使用 Python 的 Click 包从装饰器返回参数值?

[英]How do I return a parameter value from a decorator using Python's Click package?

在我的 CLI 应用程序中,我有一个配置文件,其中包含有关如何连接到 API 的信息。 可以为多种环境设置此配置:(test/prod/etc)。

我想,以确保顺利通过环境的配置文件中存在,所以我创建了一个装饰和建模它关闭的confirmation_option

这是问题的一个小例子:

# -*- coding: utf-8 -*-

import sys
import click

TEST_DICT = {
    'production': 'ProdKey'
}


def environment_option(*param_decls, **attrs):
    """
    Check that the passed environment exists
    """
    def decorator(f):
        def callback(ctx, param, value):
            if not value:
                ctx.abort()
            try:
                TEST_DICT[value]
            except KeyError:
                click.secho("Bad environment provided: {}".format(value), fg='red')
                sys.exit(1)

        attrs.setdefault('callback', callback)
        return click.option(*(param_decls or ('--environment',)), **attrs)(f)
    return decorator


@click.group()
@click.pass_context
def cli(ctx):
    """My CLI"""

@cli.command()
@environment_option('-e', '--environment', help="Environment to associate this key with", required=True)
@click.pass_context
def show_keys(ctx, environment):
    """
    List the available keys for the selected environment
    """
    click.echo("Environment:", type(environment))


if __name__ == "__main__":
    sys.exit(cli())  # pragma: no cover

如果我传入一个无效的环境,它会按预期工作。

$ python cli show-keys -e notreal
Bad environment provided: notreal

我遇到的问题是,一个有效的环境——一个不会在装饰器中触发错误的环境——当它返回到show_keys函数时没有值。 它是NoneType

$ python cli show-keys -e production

Traceback (most recent call last):
  File "/home/devuser/.virtualenvs/mycli/bin/mycli", line 11, in <module>
    load_entry_point('mycli', 'console_scripts', 'mycli')()
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/devuser/repositories/mycli/mycli/mycli/commands/config_cmds.py", line 60, in show_keys
    click.echo("Environment:", type(environment))
  File "/home/devuser/.virtualenvs/mycli/lib/python3.6/site-packages/click/utils.py", line 260, in echo
    file.write(message)
AttributeError: type object 'NoneType' has no attribute 'write'

我如何从这个装饰器而不是NoneType我的environment的价值?

没有return语句的 Python 函数,返回None 所以在回调中,你需要return TEST_DICT[value] 就像是:

def callback(ctx, param, value):
    if not value:
        ctx.abort()
    try:
        return TEST_DICT[value]
    except KeyError:
        ....

测试代码:

import sys
import click

TEST_DICT = {
    'production': 'ProdKey'
}


def environment_option(*param_decls, **attrs):
    """
    Check that the passed environment exists
    """

    def decorator(f):
        def callback(ctx, param, value):
            if not value:
                ctx.abort()
            try:
                return TEST_DICT[value]
            except KeyError:
                click.secho("Bad environment provided: {}".format(value),
                            fg='red')
                sys.exit(1)

        attrs.setdefault('callback', callback)
        return click.option(*(param_decls or ('--environment',)), **attrs)(f)

    return decorator


@click.group()
@click.pass_context
def cli(ctx):
    """My CLI"""


@cli.command('show-keys')
@environment_option('-e', '--environment',
                    help="Environment to associate this key with",
                    required=True)
@click.pass_context
def show_keys(ctx, environment):
    """
    List the available keys for the selected environment
    """
    click.echo("Environment: {}".format(environment))


if __name__ == "__main__":
    commands = (
        'show-keys -e production',
        'show-keys -e notreal',
        'show-keys --help',
        '--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)
            cli(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)]
-----------
> show-keys -e production
Environment: ProdKey
-----------
> show-keys -e notreal
Bad environment provided: notreal
-----------
> show-keys --help
Usage: test.py show-keys [OPTIONS]

  List the available keys for the selected environment

Options:
  -e, --environment TEXT  Environment to associate this key with  [required]
  --help                  Show this message and exit.
-----------
> --help
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  My CLI

Options:
  --help  Show this message and exit.

Commands:
  show-keys  List the available keys for the selected...
-----------
> 
Usage: test.py [OPTIONS] COMMAND [ARGS]...

  My CLI

Options:
  --help  Show this message and exit.

Commands:
  show-keys  List the available keys for the selected...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM