使用自定义装饰器将具有多个常用选项的命令合并到一个参数中 [英] Commands with multiple common options going into one argument using custom decorator
问题描述
我想制作一个模块,以使其非常容易构建具有许多选项的点击命令.这些选项将被提炼成传递给命令的单个对象.作为说明性示例:
I would like to make a module that makes it very simple to build click commands that share a lot of options. Those options would be distilled into a single object that is passed into the command. As an illustrative example:
from magic import magic_command
import click
@magic_command('Colored')
@click.option('--color')
def cmd(magic, color):
pass
然后,total命令将有许多--magic-...
选项进入传递到cmd
的magic
对象.我可以使用以下方法实现这一目标:
The total command would then have many --magic-...
options that go into the magic
object passed into cmd
. I was able to achieve that using the following:
def magic_command(name):
def decorator(func):
@click.option('--magic-foo')
@click.option('--magic-bar')
def wrapper(magic_foo, magic_bar, **kwargs):
print(f'initializing Magic with {magic_foo} and {magic_bar}')
magic = Magic(magic_foo, magic_bar)
func(magic, **kwargs)
try:
wrapper.__click_params__.extend(func.__click_params__)
except AttributeError:
pass
return click.command(f'{name}-Magic')(wrapper)
return decorator
但是,弄混__click_params__
似乎并不是特别干净.
However, messing with the __click_params__
doesn't seem particularly clean.
问题有点类似于 ,但是这种方法不允许我将许多魔术选项浓缩为一个魔术对象.
The question is somewhat similar to this one, however this approach does not allow me to condense the many magic options into a magic object.
要详细说明,我将不得不使用这种方法
To elaborate, with this approach I would have to do
@magic_command('Colored')
@click.option('--color')
def cmd(magic_foo, magic_bar, color):
magic = Magic(magic_foo, magic_bar)
pass
但这意味着自定义代码需要知道存在哪些魔术选项以及如何构造魔术.我想可以使用**kwargs
简化该操作,但是-理想情况下,我只想将一个就绪的magic
对象传递给cmd
.
But that means the custom code needs to be aware what magic options there are and how to construct the magic. I guess that can be simplified using **kwargs
but still - ideally I'd like to just have a ready magic
object passed to cmd
.
推荐答案
您可以很容易地通过构造如下装饰器来将多个选项提取到单个对象中:
You can distill multiple options into a single object quite simply by constructing a decorator like:
def magic_options(func):
@click.option('--magic-bar')
@click.option('--magic-foo')
def distill_magic(magic_foo, magic_bar, **kwargs):
kwargs['magic'] = Magic(magic_foo, magic_bar)
func(**kwargs)
return distill_magic
使用装饰器
然后可以将装饰器应用于命令功能,例如:
Using the decorator
You can then apply the decorator to the command function like:
@click.command('Colored-Magic')
@click.option('--color')
@magic_options
def cli(magic, color):
...
它需要应用于裸函数.这是因为click.option
返回的函数已被click框架修改,并且无法按您预期的方式工作.
It needs to be applied to the bare function. This is because the function returned by click.option
has been modified by the click framework and it won't work the way you expected.
import click
@click.command('Colored-Magic')
@click.option('--color')
@magic_options
def cli(magic, color):
click.echo(str(magic))
click.echo(color)
class Magic(object):
def __init__(self, magic_foo, magic_bar):
self.magic_foo = magic_foo
self.magic_bar = magic_bar
def __str__(self):
return "foo: {} bar: {}".format(self.magic_foo, self.magic_bar)
if __name__ == "__main__":
commands = (
'--magic-foo fooby --magic-bar barbecue',
'--magic-foo fooby',
'--magic-bar barbecue',
'',
'--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)]
-----------
> --magic-foo fooby --magic-bar barbecue
foo: fooby bar: barbecue
-----------
> --magic-foo fooby
foo: fooby bar: None
-----------
> --magic-bar barbecue
foo: None bar: barbecue
-----------
>
foo: None bar: None
-----------
> --help
Usage: test.py [OPTIONS]
Options:
--color TEXT
--magic-bar TEXT
--magic-foo TEXT
--help Show this message and exit.
这篇关于使用自定义装饰器将具有多个常用选项的命令合并到一个参数中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!