Переопределение пространства имен с помощью yaml - PullRequest
0 голосов
/ 21 октября 2018

Постановка проблемы

Я хочу, чтобы параметры, поддерживаемые в модуле python, можно было переопределить с помощью файла .yaml, потому что в некоторых случаях слишком много параметров, которые можно указывать со значениями, отличными от значений по умолчанию.

Я реализовал логику следующим образом.

parser = argparse.ArgumentParser()
# some parser.add statements that comes with default values
parser.add_argument("--config_path", default=None, type=str,
                    help="A yaml file for overriding parameters specification in this module.")
args = parser.parse_args()

# Override parameters
if args.config_path is not None:
    with open(args.config_path, "r") as f:
        yml_config = yaml.safe_load(f)
    for k, v in yml_config.items():
        if k in args.__dict__:
            args.__dict__[k] = v
        else:
            sys.stderr.write("Ignored unknown parameter {} in yaml.\n".format(k))

Проблема в том, что для некоторых опций у меня есть определенные функции / лямбда-выражения для преобразования входных строк, такие как:

parser.add_argument("--tokens", type=lambda x: x.split(","))

Чтобы применить соответствующие функции при разборе спецификаций опций в YAML, добавление такого количества операторов if не кажется хорошим решением.Ведение словаря, который изменяется соответствующим образом при введении новых опций в объекте parser, представляется излишним.Есть ли решение получить type для каждого аргумента в parser объекте?

1 Ответ

0 голосов
/ 21 октября 2018

Если элементы, которые вы добавляете в анализатор с add_argument, начинаются с --, то они на самом деле являются необязательными и обычно называются опциями.Вы можете найти эти результаты по результату метода _get_optonal_actions() экземпляра parser.

Если вы config.yaml выглядите так:

tokens: a,b,c

, то вы можете сделать:

import sys
import argparse
import ruamel.yaml


sys.argv[1:] = ['--config-path', 'config.yaml']  # simulate commandline

yaml = ruamel.yaml.YAML(typ='safe')

parser = argparse.ArgumentParser()
parser.add_argument("--config-path", default=None, type=str,
                    help="A yaml file for overriding parameters specification in this module.")
parser.add_argument("--tokens", type=lambda x: x.split(","))
args = parser.parse_args()


def find_option_type(key, parser):
    for opt in parser._get_optional_actions():
        if ('--' + key) in opt.option_strings:
           return opt.type
    raise ValueError

if args.config_path is not None:
    with open(args.config_path, "r") as f:
        yml_config = yaml.load(f)
    for k, v in yml_config.items():
        if k in args.__dict__:
            typ = find_option_type(k, parser)
            args.__dict__[k] = typ(v)
        else:
            sys.stderr.write("Ignored unknown parameter {} in yaml.\n".format(k))

print(args)

, что дает:

Namespace(config_path='config.yaml', tokens=['a', 'b', 'c'])

Обратите внимание:

  • Я использую новый API ruamel.yaml.Загрузка таким способом на самом деле быстрее, чем использование from ruamel import yaml; yaml.safe_load(), хотя ваши конфигурационные файлы, вероятно, недостаточно велики, чтобы это заметить.
  • Я использую расширение файла .yaml, как рекомендовано в официальном FAQ .Вы должны сделать то же самое, если вы не можете (например, если ваша файловая система не позволяет этого).
  • Я использую тире в строке параметра --config-path вместо подчеркивания, это несколько более естественно длявведите и автоматически преобразуйте в подчеркивание, чтобы получить действительное имя идентификатора

Возможно, вы захотите рассмотреть другой подход, в котором вы вручную анализируете sys.argv для --config-path, а затем устанавливаете значения по умолчанию для всех параметровиз файла конфигурации YAML и затем вызовите .parse_args().Выполнение действий в таком порядке позволяет вам переопределить в командной строке то, что имеет значение в файле конфигурации.Если вы делаете все по-своему, вам всегда нужно редактировать файл конфигурации, если он имеет все правильные значения, кроме одного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...