argparse: флаги из списка

#python #argparse

#python #argparse

Вопрос:

У меня есть метод в python для анализа всех запросов api, необходимых для моей библиотеки CI.

Фактически вся конфигурация этого метода хранится в файле yaml.

Пример:

 ci:
  sonar:
    name: "python_module.ci.sonar_api"
  env:
    name: "Sonar"
    required:
      AUTH_TOKEN: ["--token", "--t"]
      HOST_URL: ["--url", "--host", "--U"]
    optioal:
      TAGS: ["--tags", "--T"]
      ...
...
  

Я использую этот метод также со скриптами pythons для создания отчетов или для вызова Дженкинсом, примеры будут относительными с одним из этих скриптов

У меня есть этот фрагмент кода для построения argparse ( args_dict параметр — это добавление обязательных и необязательных значений, а project_name любая строка) :

 def parse(project_name, args_dict):
    parse_args = argparse.ArgumentParser(
        description='Request to the ' project_name ' api service.'
    )
    for _key in args_dict:
        parse_args.add_argument(
            str(', '.join(args_dict[_key])), action="store", dest=_key,
            help=project_name " " _key " ENV::" project_name.upper() "_" _key,
            default=os.environ.get(project_name.upper() "_" _key, None)
        )
    return parse_args
  

И результатом выполнения любого из этих скриптов является:

 ./sonar_report  -h
sonar_report | 2020-10-31 20:34:18.194862 |  START    | Starting process
usage: sonar_report [-h] [--token, --t AUTH_TOKEN] [--url, --host, --U HOST_URL] [--tags, --T
TAGS]

Request to the Sonar api service.

optional arguments:
  -h, --help            show this help message and exit
  --token, --t AUTH_TOKEN
                        Sonar AUTH_TOKEN ENV::SONAR_AUTH_TOKEN
  --url, --host, --U HOST_URL
                        Sonar HOST_URL ENV::SONAR_HOST_URL
  --tags, --T TAGS       Sonar TAGS ENV::SONAR_TAGS
  

Если я выполняю этот скрипт с первым определенным флагом, он работает, но проблема в том, что я использую другой флаг для любого параметра:

 usage: sonar_report [-h] [--token, --t AUTH_TOKEN] [--url, --host, --U HOST_URL] [--tags, --T
TAGS]
sonar_report: error: unrecognized arguments: --T test
  

Кто-нибудь знает, как передать флаги в виде списка?

Редактировать:

Я исключаю ошибку, игнорирующую неизвестные параметры, и печатаю значения параметров:

 def validate(argument_parser, args_dict, ignore_unknowns=None):
    try:
        if ignore_unknowns is None:
            params = vars(argument_parser.parse_args())
        else:
            _params, _unknowns = argument_parser.parse_known_args()
            params = vars(_params)
    except Exception:
        print(f"###ERROR## Trying to parse dictionary's arguments: "  
              f"{str(Exception)}")
        argument_parser.print_help()
        print()
        return None
    print(_params)
    print(_unknowns)
    .........
  

Результатом является:

 Namespace(AUTH_TOKEN='***************************',
HOST_URL='***************************', TAGS=None)
['--T', 'test']
  

Основной — это что-то вроде:

  params: project_name, env, required_args=None, ignore_unknowns=True
 return: (validate(parse(project_name, env), required_args, ignore_unknowns))
  

Комментарии:

1. add_argument Должны быть получены аргументы типа ('-T', '--tags', dest=..., help=..., etc)'. That is, each flag should be a separate string. I think you are using (‘—tags, —T’, dest=…) . Note that I used "-T", a single dash with the short flag; that's more consistent with argparse` и использование POSIX. Но ключ в том, что каждый флаг является отдельным.

Ответ №1:

Определите простой словарь:

 In [197]: dd = {'foo':['-f', '--foo']}
In [198]: key='foo'


In [206]: import argparse
In [207]: parser=argparse.ArgumentParser()
  

Использование вашего str/join для определения аргумента. Я позволяю argparse установить dest , чтобы сделать действие более понятным:

 In [208]: parser.add_argument(str(', '.join(dd[key])), help=f'help for {key}')
Out[208]: _StoreAction(option_strings=['-f, --foo'], dest='f, __foo', nargs=None, const=None, default=None, type=None, choices=None, help='help for foo', metavar=None)
In [209]: parser.print_help()
usage: ipython3 [-h] [-f, --foo F, __FOO]

optional arguments:
  -h, --help          show this help message and exit
  -f, --foo F, __FOO  help for foo
In [210]: parser.parse_args([])
Out[210]: Namespace(**{'f, __foo': None})
  

Обратите внимание, что ожидаемый флаг — это ‘-f, —foo’, комбинация, а не две строки по отдельности.

Если я использую **dd[key] вместо этого, список строк распаковывается:

 In [211]: parser=argparse.ArgumentParser()
In [212]: parser.add_argument(*dd[key], help=f'help for {key}')
Out[212]: _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help='help for foo', metavar=None)
In [213]: parser.print_help()
usage: ipython3 [-h] [-f FOO]

optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO  help for foo
In [214]: parser.parse_args([])
Out[214]: Namespace(foo=None)
In [215]: parser.parse_args(['--foo','foobar'])
Out[215]: Namespace(foo='foobar')
  

Теперь выполняется dest foo , и оба ‘-f’ и ‘—foo’ работают.

add_argument возвращает объект действия. Обычно этот возврат игнорируется, но в этом интерактивном сеансе он отображается, давая нам более четкое представление о том, что происходит.

Комментарии:

1. Да, это работает. Кроме того, я изменил короткие параметры только одним тире. Спасибо!