使用Click手动将Option对象附加到Command实例时,Python Click:NoSuchOption异常 [英] Python Click: NoSuchOption exception when manually attaching Option objects to Command instance using
问题描述
我的代码示例:
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
始终同时包含a
和b
,但如果未设置,则具有None
的值).从我的角度来看,这样做的好处是文档总是记录a
和b
.作为用户,我想我会想要的.
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屋!