使用Click手动将Option对象附加到Command实例时,Python Click:NoSuchOption异常 [英] Python Click: NoSuchOption exception when manually attaching Option objects to Command instance using

查看:558
本文介绍了使用Click手动将Option对象附加到Command实例时,Python Click:NoSuchOption异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码示例:

 import click


def std_cb(ctx, param, standardize):
    if standardize:
        opt = click.Option(param_decls=['-a'],
                           help='this option only exists when -S is set')
    else:
        opt = click.Option(param_decls=['-b'],
                           help='this option only exists when -S is not set')
    ctx.command.params.append(opt)
    return standardize


@click.command()
@click.option('-S', '--standardize/--no-standardize', is_eager=True,
              is_flag=True, default=False, callback=std_cb)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)
 

我要实现的目标是能够使用单击库为给定命令动态创建不同的选项,具体取决于对同一命令的渴望标志选项的值.

当我在CLI上以$ python cli_test.py的身份执行上述命令时,将按预期将其打印到stdout {'standardize': False, 'extra_opts': {}}.类似地,$ python cli_test.py -S打印{'standardize': True, 'extra_opts': {}},也是预期的.

当我用$ python cli_test.py --help调用内置的--help选项时,我得到:

 Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -b TEXT                         this option only exists when -S is not set
  --help                          Show this message and exit.
 

似乎暗示通过-S标志通过std_cb回调对--no-standardize特定选项的附件也可以正常工作.

类似地,$ python cli_test.py --help -S产生:

 Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -a TEXT                         this option only exists when -S is set
  --help                          Show this message and exit.
 

由于出现-S标志,现在出现-a选项.

但是,如果我尝试执行$ python cli_test.py -b hello,则会收到错误消息:click.exceptions.NoSuchOption: no such option: -b.

类似地,尽管$ python cli_test.py -S -a world会在帮助页面中相应的-S标志值下显示它们,但它们仍会生成click.exceptions.NoSuchOption: no such option: -a.

我期望从给定的代码示例中看到的是$ python cli_test.py -b hello打印{'standardize': True, 'extra_opts': {'b': 'hello'}}.

然后$ python cli_test.py -S -a world打印{'standardize': True, 'extra_opts': {'a': 'world'}}.

点击文档中,作者指出使用@click.option等同于手动创建Option实例并将其附加到Command.params列表.",因此我不确定我做错了什么.

解决方案

我不确定您的代码是否可以正常工作,但是我想知道您是否可以忍受像我在此处草绘的内容:

import click


def require_standardize_set(ctx, param, value):                                                                                                                   
    if value and not ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is set'.format(param.name))
    return value

def require_standardize_not_set(ctx, param, value):
    if value and ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is not set'.format(param.name))
    return value


@click.command()
@click.option('-S', '--standardize/--no-standardize',
              is_flag=True, default=False, is_eager=True)
@click.option('-a', help='this option requires that -S is set',
              callback=require_standardize_set)
@click.option('-b', help='this option requires that -S is not set',
              callback=require_standardize_not_set)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)

在我看来这会产生相同的结果(除了extra_opts始终同时包含ab,但如果未设置,则具有None的值).从我的角度来看,这样做的好处是文档总是记录ab.作为用户,我想我会想要的.

My code sample:

import click


def std_cb(ctx, param, standardize):
    if standardize:
        opt = click.Option(param_decls=['-a'],
                           help='this option only exists when -S is set')
    else:
        opt = click.Option(param_decls=['-b'],
                           help='this option only exists when -S is not set')
    ctx.command.params.append(opt)
    return standardize


@click.command()
@click.option('-S', '--standardize/--no-standardize', is_eager=True,
              is_flag=True, default=False, callback=std_cb)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)

What I'm trying to achieve is to be able to dynamically create different options for a given command depending on the value of an eager flag option to the same command using the click library.

When I execute the above command on the CLI as $ python cli_test.py, this is printed to stdout {'standardize': False, 'extra_opts': {}}, as expected. Similarly $ python cli_test.py -S prints {'standardize': True, 'extra_opts': {}}, also expected.

And when I invoke the built-in --help option with $ python cli_test.py --help, I get:

Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -b TEXT                         this option only exists when -S is not set
  --help                          Show this message and exit.

Which seems to suggest that the attachment of the --no-standardize specific option via the std_cb callback for the -S flag is working as well.

Similarly, $ python cli_test.py --help -S, produces:

Usage: cli_test.py [OPTIONS]

Options:
  -S, --standardize / --no-standardize
  -a TEXT                         this option only exists when -S is set
  --help                          Show this message and exit.

Now with the -a option appearing due to the presence of the -S flag.

However, if I were to try and do $ python cli_test.py -b hello, I'd get the error: click.exceptions.NoSuchOption: no such option: -b.

And similarly, $ python cli_test.py -S -a world produces click.exceptions.NoSuchOption: no such option: -a, despite them showing up in the help page under their applicable -S flag value.

What I had expected to see from the given code example is of course, $ python cli_test.py -b hello printing {'standardize': True, 'extra_opts': {'b': 'hello'}}.

And $ python cli_test.py -S -a world printing {'standardize': True, 'extra_opts': {'a': 'world'}}.

In the Click docs, the authors do state that using @click.option "is equivalent to creating an Option instance manually and attaching it to the Command.params list.", so I'm not really sure what I'm doing wrong.

解决方案

I'm not sure if your code should work, but I wonder if you could live with something like I've sketched here:

import click


def require_standardize_set(ctx, param, value):                                                                                                                   
    if value and not ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is set'.format(param.name))
    return value

def require_standardize_not_set(ctx, param, value):
    if value and ctx.params['standardize']:
        raise click.UsageError('-{} requires that -S is not set'.format(param.name))
    return value


@click.command()
@click.option('-S', '--standardize/--no-standardize',
              is_flag=True, default=False, is_eager=True)
@click.option('-a', help='this option requires that -S is set',
              callback=require_standardize_set)
@click.option('-b', help='this option requires that -S is not set',
              callback=require_standardize_not_set)
def get_options(standardize, **extra_opts):
    print(locals())


if __name__ == '__main__':
    uis = get_options.main(standalone_mode=False)

This seems to me to produce the same results (except extra_opts always includes both a and b, but with the values of None if not set). A benefit, from my point of view is that the documentation always documents both a and b. As a user, I assume I would want that.

这篇关于使用Click手动将Option对象附加到Command实例时,Python Click:NoSuchOption异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆