Поддержка произвольного количества связанных именованных аргументов с помощью Python argparse

Я хотел бы поддерживать интерфейс командной строки, где пользователи могут объявлять произвольное количество выборок, с одним или несколькими входными файлами, соответствующими каждому образцу. Что-то вроде этого:

$ myprogram.py \ --foo bar \ --sample1 input1.tsv \ --sample2 input2a.tsv input2b.tsv input2c.tsv \ --sample3 input3-filtered.tsv \ --out output.tsv 

Идея заключается в том, что ключи опций будут соответствовать шаблону --sample(\d+) , и каждая клавиша будет использовать все последующие аргументы в качестве значений параметров до тех пор, пока не встретится флаг next-or-prefixed. Для явно объявленных аргументов это обычный вариант использования модуля argparse с nargs='+' . Но так как мне нужно поддерживать произвольное количество аргументов, я не могу их явно объявить.

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

Можно ли каким-либо образом проанализировать эти параметры без существенного повторного внедрения больших частей парсера аргументов (почти) с нуля?

4 Solutions collect form web for “Поддержка произвольного количества связанных именованных аргументов с помощью Python argparse”

Если вы можете жить с немного другим синтаксисом, а именно:

 $ myprogram.py \ --foo bar \ --sample input1.tsv \ --sample input2a.tsv input2b.tsv input2c.tsv \ --sample input3-filtered.tsv \ --out output.tsv 

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

 parser.add_argument('--sample', action='append', nargs='+') 

Он создает список списков, т. Е. --sample xy --sample 1 2 будет создавать Namespace(sample=[['x', 'y'], ['1', '2']])

Как я упоминал в своем комментарии:

 import argparse argv = "myprogram.py \ --foo bar \ --sample1 input1.tsv \ --sample2 input2a.tsv input2b.tsv input2c.tsv \ --sample3 input3-filtered.tsv \ --out output.tsv" parser = argparse.ArgumentParser() parser.add_argument('--foo') parser.add_argument('--out') for x in range(1, argv.count('--sample') + 1): parser.add_argument('--sample' + str(x), nargs='+') args = parser.parse_args(argv.split()[1:]) 

дает:

 print args Namespace(foo='bar', out='output.tsv', sample1=['input1.tsv'], sample2=['input2a.tsv', 'input2b.tsv', 'input2c.tsv'], sample3=['input3-filtered.tsv']) 

С реальным sys.argv вам, вероятно, придется заменить argv.count немного более длинным. ' '.join(sys.argv).count('--sample')

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

Было бы проще сделать это число или ключ в отдельном значении аргумента и собрать связанные аргументы во вложенном списке.

 import argparse parser = argparse.ArgumentParser() parser.add_argument('--foo') parser.add_argument('--out') parser.add_argument('--sample', nargs='+', action='append', metavar=('KEY','TSV')) parser.print_help() argv = "myprogram.py \ --foo bar \ --sample 1 input1.tsv \ --sample 2 input2a.tsv input2b.tsv input2c.tsv \ --sample 3 input3-filtered.tsv \ --out output.tsv" argv = argv.split() args = parser.parse_args(argv[1:]) print(args) 

производит:

 1031:~/mypy$ python3 stack44267794.py -h usage: stack44267794.py [-h] [--foo FOO] [--out OUT] [--sample KEY [TSV ...]] optional arguments: -h, --help show this help message and exit --foo FOO --out OUT --sample KEY [TSV ...] Namespace(foo='bar', out='output.tsv', sample=[['1', 'input1.tsv'], ['2', 'input2a.tsv', 'input2b.tsv', 'input2c.tsv'], ['3', 'input3-filtered.tsv']]) 

Появились вопросы о сборе общих key:value пары key:value . В argparse нет ничего, что argparse бы прямо поддержать это. Были предложены разные вещи, но все сводилось к разбору пар.

Можно ли использовать argparse для захвата произвольного набора необязательных аргументов?

Вы добавили усложнение, что количество аргументов за ключ является переменной. Это исключает обработку '–sample1 = input1' как простых строк.

argparse расширил известный POSIX командной строки POSIX . Но если вы хотите выйти за рамки этого, тогда будьте готовы обработать аргументы либо до (sys.argv), либо после argparse (дополнительные параметры parse_known_args ).

Возможно, вам удастся сделать то, что вы ищете, с кликом, а не argparse .

Цитировать:

$ click_

Click – это пакет Python для создания красивых интерфейсов командной строки в виде композиций с минимальным количеством кода. Это «Набор для создания интерфейса командной строки». Он очень настраиваемый, но поставляется с разумными значениями по умолчанию.

Он направлен на то, чтобы сделать процесс написания инструментов командной строки быстрым и забавным, а также предотвратить любые разочарования, вызванные невозможностью реализовать предполагаемый API CLI.

Нажмите в трех точках:

  • произвольное вложение команд
  • автоматическая генерация страниц справки
  • поддерживает ленивую загрузку подкоманд во время выполнения

    Прочтите документы по адресу http://click.pocoo.org/

Одной из важных особенностей щелчка является возможность создания подкоманд (немного похожее на использование git или магии изображения), что должно позволить вам структурировать вашу командную строку как:

 myprogram.py \ --foo bar \ --sampleset input1.tsv \ --sampleset input2a.tsv input2b.tsv input2c.tsv \ --sampleset input3-filtered.tsv \ combinesets --out output.tsv 

Или даже:

 myprogram.py \ --foo bar \ process input1.tsv \ process input2a.tsv input2b.tsv input2c.tsv \ process input3-filtered.tsv \ combine --out output.tsv 

Что может быть чище, в этом случае ваш код будет иметь параметры, называемые --foo и --out и функции, называемые process и процессом combine , будут вызываться с указанными входными файлами (файлами) и не содержать никаких параметров.

  • Как сделать необязательное значение аргумента с помощью argparse?
  • Как вы получаете имя программы с помощью argparse?
  • Доступ к вариантам, переданным аргументу в argparser?
  • Использование аргументов argparse в качестве аргументов ключевого слова
  • Разрешить глобальные флаги argparse после подкоманды
  • Отключить / удалить аргумент в argparse
  • Настроить справочное сообщение argparse
  • Pip не устанавливает последнюю доступную версию из pypi (argparse в этом случае)
  • Python - лучший язык программирования в мире.