В python как заставить подпарсеры читать в аргументе родительского парсера? - PullRequest
14 голосов
/ 15 августа 2011

Вот пример кода:

import argparse

parser=argparse.ArgumentParser()
parser.add_argument('-main_arg')
subparser=parser.add_subparser()
a=subparser.add_parser('run')
a.add_argument('required_sub_arg')
a.add_argument('arg_a')
b=subparser.add_parser('b')
parser.parse_args()

Я хочу, чтобы оно читалось в -main_arg, если я введу program run required_sub_arg -main_arg -arg_a

Сейчас он не распознает -main_arg в качестве допустимого аргумента.

Ответы [ 2 ]

9 голосов
/ 15 августа 2011

PSA для недавних читателей

Поскольку этот вопрос все еще посещается в 2018 году, прежде чем делать что-либо такое сложное с argparse, рассмотрите возможность использования docopt или click . Это улучшит ваше здоровье и здоровье любого, кто может прочитать или изменить ваш код. Спасибо.

Оригинальный ответ

У вас есть несколько проблем.

Во-первых, parser.parse_args - это метод, который возвращает пространство имен аргументов parser, поэтому вы должны сделать что-то вроде

args = parser.parse_args()

Затем args.main_args, чтобы получить -main_arg от звонка типа

program -main_arg run required_sub_arg -arg_a

Ваша проблема с main_arg в том, что вы создали аргумент для parser с именем main_arg, и вы делаете вызов, подобный

program run required_sub_arg -main_arg -arg_a

, который ссылается на аргумент a с именем main_arg. Поскольку a не имеет такого аргумента, он недействителен.

Чтобы сослаться на аргумент синтаксического анализатора одного из его подпарсеров, вы должны заставить указанный подпарсер наследовать аргументы своего родителя. Это сделано с

a=parser.add_subparser('run', parents=[parser])

Вы приняли ошибочный подпарсер за дочерний парсер. См. http://docs.python.org/dev/py3k/library/argparse.html и https://code.google.com/p/argparse/issues/detail?id=54 для получения дополнительной информации.

0 голосов
/ 16 марта 2019

Для всех, кто использует argparse, который прибывает сюда, ищет способ отображения «общих» аргументов подпарасера ​​на «главном» экране справки, вот один из подходов:

import argparse
common = argparse.ArgumentParser(add_help=False)
common.add_argument('--shared', action='store_true', help='some shared arg')
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--parent', action='store_true', help='parent only arg')
subparsers = parser.add_subparsers()
run = subparsers.add_parser('run', parents=[common])
run.add_argument('--fast', action='store_true', help='run only arg')
parser.epilog = "--- Arguments common to all sub-parsers ---" \
    + common.format_help().replace(common.format_usage(), '')
args = parser.parse_args()

Основная помощь:

$ program.py -h
usage: program.py [-h] {run} ...

positional arguments:
  {run}

optional arguments:
  -h, --help  show this help message and exit
  --parent    parent only arg

--- Arguments common to all sub-parsers ---
optional arguments:
  --shared  some shared arg

run Справка подпарсера:

$ program.py run -h
usage: program.py run [-h] [--shared]

optional arguments:
  -h, --help  show this help message and exit
  --shared    some shared arg
  --fast      run only arg

Чтобы ответить на актуальный вопрос, поскольку принятый ответ не работает для меня, вот дополнительная информация о том, почемуКажется невозможным по-настоящему совместно использовать аргументы argparse с одинаковыми именами как для родительского, так и для дочернего / субпарсера.

Во-первых, проблема со следующим кодом:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-main_arg')
subparsers = parser.add_subparsers()
run = subparsers.add_parser('run', parents=[parser])
args = parser.parse_args()

Это приводит к следующей ошибке, так как родительский элемент parser и подпарсер run определяют аргумент -h / - help (по умолчанию).

Argparse.ArgumentError: argument -h/--help: conflicting option strings: -h, --help

Хотя эта ошибка может бытьизбегать путем подавления опции -h / - help (с add_help=False) на родительском или дочернем элементе, хорошо иметь опцию help на обоих уровнях.

Еще один потенциальный способ избежать конфликтующих опций помощидолжен двигаться общий аргументы для общего парсера, common:

import argparse
common = argparse.ArgumentParser(add_help=False)
common.add_argument('-main_arg', action='store_true')
parser = argparse.ArgumentParser(parents=[common])
subparsers = parser.add_subparsers()
run = subparsers.add_parser('run', parents=[common])
args = parser.parse_args()
print(args)

Хотя это работает на поверхности, на практике это работает не так, как задумано:

$ program.py run  # OK
Namespace(main_arg=False)
$ program.py run -main_arg  # OK
Namespace(main_arg=True)
$ program.py -main_arg run  # BAD: expected main_arg to be True
Namespace(main_arg=False)

Поведениенаблюдаемый при синтаксическом анализе program.py -main_arg run иллюстрирует ключевое отношение: родительский argparser и его подпарасеры являются независимыми синтаксическими анализаторами, где родительский анализирует все аргументы до позиционного аргумента подпрограммы «команда», а затем выбранный подпарсер анализирует остальные аргументы в том же пространстве имен, что и родительский, без учета атрибутов, которые могли быть установленыродитель.

...