Python argparse: получить имя подпарсерской программы в строке справки

Я пишу анализатор аргументов для модуля Python с различными подпарасерами. Моя цель - иметь общий аргумент, конструктор Argument которого передается нескольким дочерним элементам:

from argparse import ArgumentParser
parser = ArgumentParser(prog = 'master')
parser1 = ArgumentParser(help = None)
parser1.add_argument('foo', type = int, help = 'Number of times to process %(prog)s') # Line of interest
parser2 = ArgumentParser(help = None)
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number')
parser3 = ArgumentParser(help = None)
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text')
subparsers = parser.add_subparsers()
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2])
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3])
parser.parse_args('prog1 -h'.split())

Желаемый результат будет что-то вроде

usage: master prog1 [-h] [--bar BAR] foo

positional arguments:
  foo            Number of times to process prog1

optional arguments:
  -h, --help     show this message and exit
  --bar          Start at this number

Когда я использую эту точную настройку, я получаю master prog1 вместо prog1 в строке помощи для foo, Что я должен изменить в строке, отмеченной #Line of interest получить желаемый результат?

2 ответа

Я могу объяснить, что происходит, но, возможно, не смогу предложить решение.

Короткий ответ: sp1.prog используется как в его usage формат и как %(prog)s значение в строке помощи. И это построено с этим usage линия в виду.

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

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2])

создает парсер и добавляет аргументы из parents, add_parser это метод class _SubParsersAction (подпункт Действие класс). И prog Атрибут для этого парсера создается с помощью:

     if kwargs.get('prog') is None:
        kwargs['prog'] = '%s %s' % (self._prog_prefix, name)

Вы должны быть в состоянии увидеть этот атрибут с print(sp1.prog) (Я ожидаю "мастер прог1"). Это значение, которое используется в usage в любой строке справки с %(prog)s,

subparsers._prog_prefix происходит от parser.prog (см. add_subparsers код для деталей). Но вы также можете указать prog параметр:

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1')

Это должно исправить строку в help линия. Но это также изменит строку usage,

Вы также можете дать явный указатель usage:

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1', usage='master prog1 ...')

Без операции на HelpFormatter Я не думаю, что вы можете изменить prog в справочных линиях, не меняя их в использовании.

И учитывая путь parents работает, вы не можете изменить линию помощи для prog1 foo не меняя также prog2 foo, parents копирует объекты Action по ссылке, поэтому два подпарсера разделяют foo Объект действия.

Вы много должны отказаться от parents подход, по крайней мере, для этого аргумента, и жестко закодировать имя. Если вам нужно добавить аргумент в несколько подпарсеров, напишите небольшую служебную функцию, чтобы облегчить это. parents Механизм - это просто (обычно) удобство, то, что экономит время при наборе текста / редактировании.

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

Этот модифицированный скрипт проиллюстрирует мои очки

parser = ArgumentParser(prog = 'master')

parser1 = ArgumentParser(add_help = False)
fooarg=parser1.add_argument('foo', type = int, help = 'foo prog: %(prog)s') # Line of interest
parser2 = ArgumentParser(add_help = False)
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number')
parser3 = ArgumentParser(add_help = False)
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text')

subparsers = parser.add_subparsers(prog='subparsers')
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='name1')
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3])

#parser.print_help()

# fooarg is an Action for both subparsers
# print(fooarg.help)
# fooarg.help = 'FOO HELP'

print('==>sp1 prog:', sp1.prog)
sp1.print_help()
print('==>sp2 prog:', sp2.prog)
sp2.print_help()

sp1.prog = 'custom'
sp1.print_help()

# addition
fooarg.default = 'default'
fooarg.metavar = 'META'
fooarg.help = 'prog: %(prog)s, dest=%(dest)s, nargs=%(nargs)s, type=%(type)s, default=%(default)s'
sp1.print_help()

Этот последний бит добавляет кучу атрибутов Action к справке. Но prog единственный, который исходит от parser:

positional arguments:
  META        prog: custom, dest=foo, nargs=None, type=int, default=default

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

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

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