Възможно ли е в 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)]
"""

Първата е собствена 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