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

Далее будет установлена ​​взаимоисключающая группа, в которой допустим только один из «-a» или «-b».

import argparse

parser = argparse.ArgumentParser()
group = parser.add_add_mutually_exclusive_group()
group.add_argument('-a')
group.add_argument('-b')

Вместо этого я хотел бы предоставить аргументы «-a» и «-b» из других парсеров. Что-то типа:

a_parser = argparse.ArgumentParser()
a_parser.add_argument('-a')

b_parser = argparse.ArgumentParser()
b_parser.add_argument('-b')

parser = argparse.ArgumentParser()
group = parser.add_add_mutually_exclusive_group()
group.SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER(a_parser)
group.SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER(b_parser)

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

parser.parse_args(['-a', '1', '-b', '1'])

Проблема в том, что я не знаю, существует ли логика SOME_HOW_ADD_ARGS_FROM_OTHER_PARSER, которую мне не хватает. Если он существует, я не знаю, как это сделать. У кого-нибудь есть какие-либо идеи?


person Wren T.    schedule 23.01.2015    source источник
comment
Почему вы создаете несколько парсеров? Что вы действительно пытаетесь сделать?   -  person Kevin    schedule 24.01.2015
comment
Я хочу создать несколько наборов аргументов, которые применяются к определенным подкомандам. Для некоторых подкоманд имеет смысл использовать -a и -b, тогда как для других имеет смысл использовать только -a. Опции -a и -b должны быть взаимоисключающими, если они доступны в одной и той же подкоманде.   -  person Wren T.    schedule 29.01.2015


Ответы (1)


Да, способ есть, но он использует какие-то скрытые атрибуты парсера. Я использую идею, разработанную для

http://bugs.python.org/issue10984 argparse add_mutually_exclusive_group should accept existing arguments to register conflicts

Создайте 2 родительских парсера с add_help=False (чтобы предотвратить конфликты из-за аргумента -h - это стандартная процедура родительского парсера)

a_parser = argparse.ArgumentParser(add_help=False)
aaAction = a.parser.add_argument('-a')
b_parser = argparse.ArgumentParser(add_help=False)
bbAction = b_parser.add_argument('-b')

parser=argparse.ArgumentParser(parents=[a_parser, b_parser])
group=parser.add_mutually_exclusive_group()

На данный момент parser имеет 3 действия (аргумента), которые можно увидеть в атрибуте 'private', _actions:

print parser._actions
""" 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['-a'], dest='a', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None),
 _StoreAction(option_strings=['-b'], dest='b', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]
"""

1-й собственный help, остальные унаследованы от родителей. Я также сохранил указатели на эти ранее, aaAction и bbAction. Теперь нам просто нужно добавить их в список _group_actions group:

group._group_actions.append(parser._actions[1]) # or (aaAction)
group._group_actions.append(parser._actions[2]) # or (bbAction)

Если бы патч 10984 был реализован, мы могли бы написать:

group = parser.add_mutually_exclusive_group(aaAction, bbAction)

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

Мы можем проверить это с помощью:

In [31]: print parser.format_help()
usage: ipython [-h] [-a A | -b B]

optional arguments:
  -h, --help  show this help message and exit
  -a A
  -b B


In [32]: parser.parse_args(['-a','a'])
Out[32]: Namespace(a='a', b=None)

In [33]: parser.parse_args(['-a','a','-b','b'])
usage: ipython [-h] [-a A | -b B]
ipython: error: argument -b: not allowed with argument -a
An exception has occurred, use %tb to see the full traceback.

Это зависит от нескольких частей информации:

  • add_argument возвращает указатель на только что созданное действие.

  • parents добавляет действия в новый парсер, просто копируя точки действий, т.е. по ссылке.

  • зная, где parse и group хранят свои соответствующие списки действий.

  • зная, чем добавление действия в группу отличается от добавления его в парсер (не очень).

Я рекомендую тестировать такой код в интерактивной оболочке (например, IPython), где вы можете посмотреть атрибуты parser и group. И держите копию Lib/argparse.py под рукой. :)

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

person hpaulj    schedule 23.01.2015