Python Click — укажите аргументы и параметры из файла конфигурации

Учитывая следующую программу:

#!/usr/bin/env python
import click

@click.command()
@click.argument("arg")
@click.option("--opt")
@click.option("--config_file", type=click.Path())
def main(arg, opt, config_file):
    print("arg: {}".format(arg))
    print("opt: {}".format(opt))
    print("config_file: {}".format(config_file))
    return

if __name__ == "__main__":
    main()

Я могу запустить его с аргументами и параметрами, предоставленными через командную строку.

$ ./click_test.py my_arg --config_file my_config_file
arg: my_arg
opt: None
config_file: my_config_file

Как предоставить файл конфигурации (в ini? yaml? py? json?) для --config_file и принять его содержимое в качестве значения аргументов и параметров?

Например, я хочу, чтобы my_config_file содержал

opt: my_opt

и вывод программы показывает:

$ ./click_test.py my_arg --config_file my_config_file
arg: my_arg
opt: my_opt
config_file: my_config_file

Я нашел функцию callback, которая показалась мне полезной, но я не смог найти способ изменить аргументы/параметры одного уровня для той же функции.


person Calvin    schedule 22.09.2017    source источник
comment
Вы пробовали: github.com/jenisys/click-configfile?   -  person Stephen Rauch    schedule 22.09.2017
comment
Я надеялся, что этого можно добиться без внешнего пакета   -  person Calvin    schedule 22.09.2017


Ответы (1)


Это можно сделать, переопределив метод click.Command.invoke(), например:

Пользовательский класс:

def CommandWithConfigFile(config_file_param_name):

    class CustomCommandClass(click.Command):

        def invoke(self, ctx):
            config_file = ctx.params[config_file_param_name]
            if config_file is not None:
                with open(config_file) as f:
                    config_data = yaml.safe_load(f)
                    for param, value in ctx.params.items():
                        if value is None and param in config_data:
                            ctx.params[param] = config_data[param]

            return super(CustomCommandClass, self).invoke(ctx)

    return CustomCommandClass

Использование пользовательского класса:

Затем, чтобы использовать пользовательский класс, передайте его в качестве аргумента cls декоратору команды, например:

@click.command(cls=CommandWithConfigFile('config_file'))
@click.argument("arg")
@click.option("--opt")
@click.option("--config_file", type=click.Path())
def main(arg, opt, config_file):

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

# !/usr/bin/env python
import click
import yaml

@click.command(cls=CommandWithConfigFile('config_file'))
@click.argument("arg")
@click.option("--opt")
@click.option("--config_file", type=click.Path())
def main(arg, opt, config_file):
    print("arg: {}".format(arg))
    print("opt: {}".format(opt))
    print("config_file: {}".format(config_file))


main('my_arg --config_file config_file'.split())

Результаты теста:

arg: my_arg
opt: my_opt
config_file: config_file
person Stephen Rauch    schedule 24.09.2017
comment
Любые мнения о том, как это сравнивается с click-config или click-configfile? - person eric.frederich; 15.03.2018
comment
@ eric.frederich, это было просто быстрое упражнение, чтобы продемонстрировать, как вы можете создавать свои собственные вещи, поэтому никаких мнений за / против против библиотек. - person Stephen Rauch; 15.03.2018