2017-01-19 2 views
1

Я пытаюсь создать команду, какКак argparse с nargs + и подкомандами

prog [-h] [-i ID [ID ...]] | -x [SOMETHING] 
    {cmd1,cmd2,cmd3}... 

Так в основном на верхнем уровне у меня есть синтаксический анализатор, который имеет взаимную EXLUSIVE группу для -i и -x , а затем следуя этим (и, возможно, другим) параметрам, у меня есть команда, которую я хочу запустить. Каждая команда имеет свой собственный набор опций, которые они используют. Я могу заставить команды работать нормально с add_subparsers(), но проблема, с которой я сталкиваюсь, - это когда я пытаюсь добавить аргумент в корневой парсер с nargs='+'. Когда я это делаю, он перекрывает все аргументы для -i, полагая, что команда является аргументом, а не идентификатором.

Есть ли способ обойти это? Похоже, что ему придется просмотреть аргументы в -i, ища командное слово, а затем сообщить argparse, что он должен возобновить разбор в этой точке.

+0

Вы можете показать нам [mcve]/ваш код, если он не слишком большой? –

+1

Checkout [Click] (http://click.pocoo.org/5/) для создания CLI с помощью python и сохранения головной боли. – garnertb

+0

@garnertb +1. Можете подтвердить, что 'click' отлично и отлично справляется с подкомандами. – Tagc

ответ

3

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

prog -i id1 id2 cmd1 -foo 3 .... 

и это дает какое-то предупреждение о не найдя {cmd1,cmd2,cmd3}. Точная ошибка может отличаться, поскольку в некоторых версиях subparsers на самом деле не требуется.

В любом случае, аргументы -i - это ['id1','id2','cmd1'], все до следующего -. Для основного анализатора аргумент подпараметров - это еще один номер positionalchoices). При распределении строк до -i он не проверяет соответствие строки одной из cmds. Он просто смотрит, начинается ли это с - или нет.

Единственный способ, которым вы можете использовать nargs='+' (или '*') в контексте, - включить в него другой флаг, например,

prog -i id1 id2 -x 3 cmd1 --foo ... 

Я понимаю, что идет против вашей группы mutually_exclusive.

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

На боковой панели

Argparse nargs="+" is eating positional argument

Это аналогично, за исключением, что ваш следующий позиционная является subparsers CMD.

==============

Позиционная с '+' будет работать прямо перед subparsers CMD

usage: prog [-h] foo [foo ...] {cmd1,cmd2} ... 

In [160]: p1.parse_args('1 22 3 cmd1'.split()) 
Out[160]: Namespace(cmd='cmd1', foo=['1', '22', '3']) 

Но это потому, что строки для foo и cmd выделяются одним шаблоном regex.

В

usage: prog [-h] [--bar BAR [BAR ...]] {cmd1,cmd2} ... 

строки выделяются bar без ссылки на потребности следующих позиционной, cmd. Как показано в предложенных исправлениях для http://bugs.python.org/issue9338, изменение этого поведения не является тривиальным изменением. Для этого требуется дополнительный цикл проб и ошибок.

+1

В качестве следствия этого: 'nargs = '+'', как правило, плохо работает с другими. Или используйте один аргумент несколько раз ('-i id1 -i id2 cmd1') или задайте параметр для принятия одного аргумента синтаксического анализа (' -i id1, id2 cmd1'). – chepner

+0

Да, это простое решение, с которым я столкнулся, но это не идеально. Я бы хотел, чтобы он был достаточно умным, чтобы знать, что команды являются параметрами и продолжают синтаксический анализ, не зная «секретный соус» для разделения разделенных запятыми списков, и т. Д. В идеале анализатор будет проверять id2 и понимать, что это является командой и анализируется как таковой. По сути, я хочу сделать «peek next id». Если нет в командах, добавьте в id, else проанализируйте как команду « – FuriousGeorge

+0

Это противоречит основному методу анализа« argparse ». 'optparse' может делать что-то вроде того, что вы хотите. Но 'argparse' полностью работает с строками позиции и флагов. Он не «смотрит вперед», чтобы увидеть, соответствует ли следующая строка некоторым критериям ценности. Сначала он выделяет строки для действия, а затем запускает тесты типа «type» и «choice», а не наоборот. – hpaulj

 Смежные вопросы

  • Нет связанных вопросов^_^