使用自定义装饰器将具有多个常用选项的命令合并到一个参数中 [英] Commands with multiple common options going into one argument using custom decorator

查看:64
本文介绍了使用自定义装饰器将具有多个常用选项的命令合并到一个参数中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个模块,以使其非常容易构建具有许多选项的点击命令.这些选项将被提炼成传递给命令的单个对象.作为说明性示例:

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-...选项进入传递到cmdmagic对象.我可以使用以下方法实现这一目标:

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屋!

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