2016-12-28 10 views
1

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

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, чтобы получить желаемый результат?

ответ

0

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

Click_ в трех точках:

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

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

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

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

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

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

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

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

subparsers._prog_prefix получен из parser.prog (см. Код). Но вы также можете указать prog параметр:

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

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

Вы также мог бы дать subparser явного usage:

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

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

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

Вы должны отказаться от подхода 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() 

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

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