如何使用Click CLI框架接受不确定数量的选项(以及如何查询其名称/值)? [英] How to accept an indefinite number of options (and how to query their names/values) using click CLI framework?

查看:94
本文介绍了如何使用Click CLI框架接受不确定数量的选项(以及如何查询其名称/值)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将无限数量的选项传递给click CLI.我也不知道选项名称.我通过使用名为conf的选项来解决此问题.它接受假定代表JSON对象的字符串.

I want to pass an unlimited number of options to a click CLI. I don't know Option names either. I'm getting around this issue by using an option named conf. It accepts a string that is assumed to represent a JSON object.

我所做的:

@click.command()
@click.option('--conf', type=str)
def dummy(conf):
    click.echo('dummy param {}'.format(conf))

我如何使用它:

>python main.py dummy --conf='{"foo": "bar", "fizz": "buzz"}'

我想做什么:

@click.command()
#some magic stuff
def dummy(**kwargs):
    click.echo('dummy param {}'.format(**kwargs))

我要如何使用它:

>python main.py dummy --foo=bar --fizz=buzz

推荐答案

您可以钩住解析器并使它知道从命令行给出的每个选项,例如:

You can hook the parser and make it aware of each option given from the command line like:

import click

class AcceptAllCommand(click.Command):

    def make_parser(self, ctx):
        """Hook 'make_parser' and allow the opt dict to find any option"""
        parser = super(AcceptAllCommand, self).make_parser(ctx)
        command = self

        class AcceptAllDict(dict):

            def __contains__(self, item):
                """If the parser does no know this option, add it"""

                if not super(AcceptAllDict, self).__contains__(item):
                    # create an option name
                    name = item.lstrip('-')

                    # add the option to our command
                    click.option(item)(command)

                    # get the option instance from the command
                    option = command.params[-1]

                    # add the option instance to the parser
                    parser.add_option(
                        [item], name.replace('-', '_'), obj=option)
                return True

        # set the parser options to our dict
        parser._short_opt = AcceptAllDict(parser._short_opt)
        parser._long_opt = AcceptAllDict(parser._long_opt)

        return parser

使用自定义类:

要使用自定义类,只需将类传递给click.command()装饰器,例如:

Using the Custom Class:

To use the custom class, just pass the class to the click.command() decorator like:

@click.command(cls=AcceptAllCommand)
def my_command(**kwargs):
    ...

这是如何工作的?

之所以有用,是因为click是一个设计良好的OO框架. @click.command()装饰器通常会实例化click.Command对象,但允许使用cls参数覆盖此行为.因此,在我们自己的类中从click.Command继承并超越所需的方法是相对容易的事情.

How does this work?

This works because click is a well designed OO framework. The @click.command() decorator usually instantiates a click.Command object but allows this behavior to be over-ridden with the cls parameter. So it is a relatively easy matter to inherit from click.Command in our own class and over ride the desired methods.

在这种情况下,我们将覆盖make_parser()并将选项字典替换为我们自己的dict类.在我们的dict中,我们重写了__contains__()魔术方法,在其中,我们为解析器填充了一个与要查找的名称匹配的选项(如果该名称尚不存在的话).

In this case, we override make_parser() and replace the option dicts with a dict class of our own. In our dict we override the __contains__() magic method, and in it we populate the parser with an option matching the name that is being looked for, if that name does not already exist.

@click.command(cls=AcceptAllCommand)
def dummy(**kwargs):
    click.echo('dummy param: {}'.format(kwargs))

if __name__ == "__main__":
    import time
    cmd = '--foo=bar --fizz=buzz'

    print('Click Version: {}'.format(click.__version__))
    print('Python Version: {}'.format(sys.version))
    print('-----------')
    print('> ' + cmd)
    time.sleep(0.1)
    dummy(cmd.split())

结果:

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)]
-----------
> --foo=bar --fizz=buzz
dummy param: {'foo': 'bar', 'fizz': 'buzz'}        

这篇关于如何使用Click CLI框架接受不确定数量的选项(以及如何查询其名称/值)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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