Как принять неопределенное количество опций (и как запросить их имена / значения), используя инфраструктуру щелчка CLI?

1

Я хочу передать неограниченное количество параметров клику CLI. Я также не знаю имена опций. Я обойду эту проблему, используя опцию conf. Он принимает строку, которая предполагается представлять собой объект JSON.

Что я сделал:

@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
Теги:
python-click

1 ответ

1

Вы можете подключить синтаксический анализатор и сообщить ему о каждом параметре, указанном в командной строке, например:

Пользовательский командный класс:

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, 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() например:

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

Как это работает?

Это работает, потому что клик - это хорошо разработанная OO-структура. @click.command() обычно создает экземпляр объекта click.Command но позволяет этому поведению click.Command параметр cls. Так что относительно легко наследовать от click.Command в нашем собственном классе и над click.Command желаемые методы.

В этом случае мы переопределяем make_parser() и заменяем опцию dicts собственным классом dict. В нашем dict мы переопределяем магический метод __contains__(), и в нем мы заполняем синтаксический анализатор опцией, соответствующей __contains__() имени, если это имя еще не существует.

Тестовый код:

@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'}        

Ещё вопросы

Сообщество Overcoder
Наверх
Меню