2013-11-20 2 views
21

У моего argparse есть только 3 флага (store_true) на верхнем уровне, все остальное обрабатывается через подпарамеры. Когда я запускаю myprog.py --help, на выходе отображается список всех подкоманд, таких как normal, {sub1, sub2, sub3, sub4, ...}. Итак, по умолчанию работает отлично ...argparse subparser monolithic help output

Обычно я не помню точное имя подкоманды, которое мне нужно, и все его варианты. Так что я в конечном итоге делает 2 справки Lookups:

myprog.py --help 
myprog.py sub1 --help 

Я делаю это так часто, что я решил втиснуть это в один шаг. Я бы предпочел, чтобы мой помощник справился с огромным сводкой, а затем я просматриваю список вручную. Я считаю, что это намного быстрее (по крайней мере для меня).

Я использовал RawDescriptionHelpFormatter и печатал длинный вывод справки вручную. Но теперь у меня много подкоманд, и мне становится больно управлять.

Есть ли способ получить подробный вывод справки с помощью всего одного вызова программы?

Если нет, то как я могу перебирать подпараметры моего экземпляра argparse, а затем извлекать вывод справки отдельно от каждого из них (который позже я буду склеивать)?


Вот краткое описание моей установки argparse. Я очистил/раздели код честным битом, так что это может не работать без какой-либо помощи.

parser = argparse.ArgumentParser(
     prog='myprog.py', 
     formatter_class=argparse.RawDescriptionHelpFormatter, 
     description=textwrap.dedent(""" You can manually type Help here """)) 

parser.add_argument('--debuglog', action='store_true', help='Verbose logging for debug purposes.') 
parser.add_argument('--ipyonexit', action='store_true', help='Drop into an embeded Ipython session instead of exiting command.') 

subparser = parser.add_subparsers() 

### --- Subparser B 
parser_b = subparser.add_parser('pdfreport', description="Used to output reports in PDF format.") 
parser_b.add_argument('type', type=str, choices=['flatlist', 'nested', 'custom'], 
         help="The type of PDF report to generate.") 
parser_b.add_argument('--of', type=str, default='', 
         help="Override the path/name of the output file.") 
parser_b.add_argument('--pagesize', type=str, choices=['letter', '3x5', '5x7'], default='letter', 
         help="Override page size in output PDF.") 
parser_b.set_defaults(func=cmd_pdf_report) 

### ---- Subparser C 
parser_c = subparser.add_parser('dbtables', description="Used to perform direct DB import/export using XLS files.") 
parser_c.add_argument('action', type=str, choices=['push', 'pull', 'append', 'update'], 
         help="The action to perform on the Database Tables.") 
parser_c.add_argument('tablename', nargs="+", 
         help="The name(s) of the DB-Table to operate on.") 
parser_c.set_defaults(func=cmd_db_tables) 

args = parser.parse_args() 
args.func(args) 
+0

Покажите нам крошечный пример с некоторым кодом, только пара вариантов и пара подпараллелей. –

ответ

9

Это немного сложнее, так как argparse не предоставляет список определенных суб-парсеров непосредственно. Но это может быть сделано:

import argparse 

# create the top-level parser 
parser = argparse.ArgumentParser(prog='PROG') 
parser.add_argument('--foo', action='store_true', help='foo help') 
subparsers = parser.add_subparsers(help='sub-command help') 

# create the parser for the "a" command 
parser_a = subparsers.add_parser('a', help='a help') 
parser_a.add_argument('bar', type=int, help='bar help') 

# create the parser for the "b" command 
parser_b = subparsers.add_parser('b', help='b help') 
parser_b.add_argument('--baz', choices='XYZ', help='baz help') 
# print main help 
print(parser.format_help()) 

# retrieve subparsers from parser 
subparsers_actions = [ 
    action for action in parser._actions 
    if isinstance(action, argparse._SubParsersAction)] 
# there will probably only be one subparser_action, 
# but better save than sorry 
for subparsers_action in subparsers_actions: 
    # get all subparsers and print help 
    for choice, subparser in subparsers_action.choices.items(): 
     print("Subparser '{}'".format(choice)) 
     print(subparser.format_help()) 

Этот пример должен работать на Python 2.7 и Python 3. Пример синтаксического анализатора от Python 2.7 documentation on argparse sub-commands.

Осталось только добавить новый аргумент для полной справки или заменить встроенный -h/--help.

+0

Отличный пример. Это создает хороший результат для меня. Я не уверен, как переопределить аргумент -h/- help в моем случае, поскольку необязательные аргументы не любят следовать моим подпарамерам. Хотя, я могу просто определить другого подпараметра с именем «help», как самого последнего, и он может проверять все, что было добавлено до него. – user2097818

2

Более простой способ перебора subparsers в примере Adaephon является

for subparser in [parser_a, parser_b]: 
    subparser.format_help() 

Python действительно позволяет получить доступ скрытые атрибуты, как parser._actions, но это не рекомендуется. Так же легко создавать свой собственный список при определении парсера. То же самое относится к тому, чтобы делать специальные вещи с аргументами. add_argument и add_subparser возвращают свои соответствующие Action и Parser объекты по причине.

Если бы я делал подкласс ArgumentParser, я был бы вправе использовать _actions. Но для одного приложения, создание моего собственного списка было бы более ясным.


Пример:

import argparse 

parser = argparse.ArgumentParser() 
parser.add_argument('mainpos') 
parser.add_argument('--mainopt') 
sp = parser.add_subparsers() 
splist = [] # list to collect subparsers 
sp1 = sp.add_parser('cmd1') 
splist.append(sp1) 
sp1.add_argument('--sp1opt') 
sp2 = sp.add_parser('cmd2') 
splist.append(sp2) 
sp2.add_argument('--sp2opt') 

# collect and display for helps  
helps = [] 
helps.append(parser.format_help()) 
for p in splist: 
    helps.append(p.format_help()) 
print('\n'.join(helps)) 

# or to show just the usage 
helps = [] 
helps.append(parser.format_usage()) 
for p in splist: 
    helps.append(p.format_usage()) 
print(''.join(helps)) 

Комбинированный дисплей 'использование' является:

usage: stack32607706.py [-h] [--mainopt MAINOPT] mainpos {cmd1,cmd2} ... 
usage: stack32607706.py mainpos cmd1 [-h] [--sp1opt SP1OPT] 
usage: stack32607706.py mainpos cmd2 [-h] [--sp2opt SP2OPT] 

Дисплей комбинированный помогает долго и излишним.Его можно редактировать по-разному, либо после форматирования, либо с помощью специальных форм помощи. Но кто собирается делать такой выбор?

-1

У меня есть несколько простых оберток, которые хранят различные ссылки (Parser, SubParser, StoreAction) последовательно, для легкой итерации во время создания справки.

Теперь я получаю организованный, подробный, автоматически генерируемый вывод справки. Когда я получу шанс, я опубликую обзор.

Существует один недостаток, связанный с созданным содержимым справки по необязательным аргументам: это не очень хорошо. Для улучшения этих результатов помощи потребуется больше, чем обертка (если мы хотим сохранить ее в чистоте). Но если вам нужен хороший обзор справки для меняющихся программ, это должно удовлетворить большинство.

8

Вот полный soulution с помощью пользовательского обработчика (почти весь код из @Adaephon ответа):

import argparse 


class _HelpAction(argparse._HelpAction): 

    def __call__(self, parser, namespace, values, option_string=None): 
     parser.print_help() 

     # retrieve subparsers from parser 
     subparsers_actions = [ 
      action for action in parser._actions 
      if isinstance(action, argparse._SubParsersAction)] 
     # there will probably only be one subparser_action, 
     # but better save than sorry 
     for subparsers_action in subparsers_actions: 
      # get all subparsers and print help 
      for choice, subparser in subparsers_action.choices.items(): 
       print("Subparser '{}'".format(choice)) 
       print(subparser.format_help()) 

     parser.exit() 

# create the top-level parser 
parser = argparse.ArgumentParser(prog='PROG', add_help=False) # here we turn off default help action 

parser.add_argument('--help', action=_HelpAction, help='help for help if you need some help') # add custom help 

parser.add_argument('--foo', action='store_true', help='foo help') 
subparsers = parser.add_subparsers(help='sub-command help') 

# create the parser for the "a" command 
parser_a = subparsers.add_parser('a', help='a help') 
parser_a.add_argument('bar', type=int, help='bar help') 

# create the parser for the "b" command 
parser_b = subparsers.add_parser('b', help='b help') 
parser_b.add_argument('--baz', choices='XYZ', help='baz help') 

parsed_args = parser.parse_args() 
+1

Возможно, лучше использовать 'parser.add_argument ('-h', '--help', action = _HelpAction, help = 'показать это справочное сообщение и выйти')', чтобы соответствовать умолчанию 'argparse'' --help' вариант. – asmeurer

0

Я также был в состоянии напечатать краткую справку по командам с помощью _choices_actions.

def print_help(parser): 
    print(parser.description) 
    print('\ncommands:\n') 

    # retrieve subparsers from parser 
    subparsers_actions = [ 
     action for action in parser._actions 
     if isinstance(action, argparse._SubParsersAction)] 
    # there will probably only be one subparser_action, 
    # but better save than sorry 
    for subparsers_action in subparsers_actions: 
     # get all subparsers and print help 
     for choice in subparsers_action._choices_actions: 
      print(' {:<19} {}'.format(choice.dest, choice.help)) 
Смежные вопросы