команды и группы argparse: настройка диалогового окна справки в подкоманде в своей собственной группе, не скрываясь в диалоговом окне справки верхнего уровня

#python #command-line-interface #argparse

Вопрос:

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

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

Вот код, который я разработал:

 # imports
import argparse

# create the top-level parser
parser = argparse.ArgumentParser(prog="example", add_help=False, epilog="A very cool program")

# add top-level groups
toplevel = parser.add_argument_group("Global arguments")
toplevel.add_argument("-g", "--global", action="store_true", help="A global argument.")

help = parser.add_argument_group("Help dialog")
help.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# create subparser
subparsers = parser.add_subparsers(title="Available subcommands", dest="subcommand")

# create the parser for the "a" subcommand
parser_a = subparsers.add_parser("a", add_help=False)

# add groups for subcommand "a"
required_a = parser_a.add_argument_group("Required arguments")
required_a.add_argument("--bar", type=int, help="Flag bar help", required=True)

help_a = parser_a.add_argument_group("Help dialog")
help_a.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# create the parser for the "b" command
parser_b = subparsers.add_parser("b", add_help=False)

# add groups for subcommand "b"
required_b = parser_b.add_argument_group("Required arguments")
required_b.add_argument("--baz", help="Flag baz help", required=True)

optional_b = parser_b.add_argument_group("Optional arguments")
optional_b.add_argument("--tas", help="Flag tas help")

help_b = parser_b.add_argument_group("Help dialog")
help_b.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="Show this help message and exit.")

# parse arguments
args = parser.parse_args()

# provide args to main
print(args)
 

Справка верхнего уровня выглядит следующим образом:

 $ example -h
usage: example [-g] [-h] {a,b} ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available sub-commands:
  {a,b}

A very cool program
 

Который, как вы можете видеть, не отображает сообщение справки в подкомандах.
Чтобы они отображались, мне пришлось бы избавиться от add_help=False них при создании parser_a , parser_b но затем, как и ожидалось, это вызвало бы проблему, когда я определил бы свой собственный флаг справки.

По сути, я хотел бы иметь лучшее из обоих миров, где мой основной диалог будет:

 $ example -h
usage: example [-g] [-h] {a,b} ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available sub-commands:
  {a,b}
    a           Help for sub-command a.
    b           Help for sub-command b.

A very cool program
 

И подкоманды будут:

 $ example a -h
usage: example a --bar BAR [-h]

Required arguments:
  --bar BAR   Flag bar help

Help dialog:
  -h, --help  Show this help message and exit.
 

После просмотра исходного кода argparse, будет ли этот вариант conflict_handler возможным решением? Можно ли было бы указать ему игнорировать исходное диалоговое окно справки, которое отображается в разделе позиционные аргументы, которые мне не нужны, и вместо этого показывать его в моей собственной группе, но без его полного отключения?

TL; DR: ищу изменения, необходимые для моего скрипта Python, чтобы argparse выводил два предыдущих блока кода.

Примечание: причина, по которой «help-dialog» написано в заголовке, заключается в том, что переполнение стека не позволяет мне писать мировую «справку» в заголовке, независимо от того, где она написана в предложении.

Комментарии:

1. При обычной настройке example -h подразделов будут отображаться группы и подкоманды основного анализатора ( subparsers фактически это позиционный аргумент основного анализатора). example a -h , передает синтаксический parser_a анализ, и он, в свою очередь, отвечает на -h , показывая свои собственные группы. Основной анализатор ничего не знает об аргументах subparser, и то же самое для subparser.

2. Я полагаю, что ваши заменители ‘help-dialog’ ведут себя точно так же, но я не могу сказать наверняка. Неясно, чего вам не хватает или чего вы ожидаете.

3. Я отредактировал сообщение, чтобы сделать его более понятным, потому что ограничение на количество символов в комментариях довольно низкое. Я ожидаю, что под разделом подкоманды в главном диалоговом окне справки появится справочное сообщение, а в диалоговом окне справки по вспомогательной команде команда help будет находиться внутри ее собственной группы. По какой-то причине это довольно сложно объяснить, но если вы видите последние 2 блока кода, это именно то, чего я пытаюсь достичь.

Ответ №1:

Ваш код выдает:

 1138:~/mypy$ python3 stack69633930.py -h
usage: example [-g] [-h] {a,b} ...

Global arguments:
  -g, --global  A global argument.

Help dialog:
  -h, --help    Show this help message and exit.

Available subcommands:
  {a,b}

A very cool program
1140:~/mypy$ python3 stack69633930.py a -h
usage: example a --bar BAR [-h]

Required arguments:
  --bar BAR   Flag bar help

Help dialog:
  -h, --help  Show this help message and exit.
 

С помощью обычной справки

 1140:~/mypy$ python3 stack69633930-1.py -h
usage: example [-h] [-g] {a,b} ...

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

Global arguments:
  -g, --global  A global argument.

Available subcommands:
  {a,b}

A very cool program
1142:~/mypy$ python3 stack69633930-1.py a -h
usage: example a [-h] --bar BAR

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

Required arguments:
  --bar BAR   Flag bar help
 

Единственные различия, которые я вижу, — это группа «Диалог справки» вместо «необязательных аргументов» и место [-h] в использовании.

Чтобы получить «справку» для подкоманд:

 1155:~/mypy$ python3 stack69633930-1.py -h
usage: example [-h] [-g] {a,b} ...

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

Global arguments:
  -g, --global  A global argument.

Available subcommands:
  {a,b}
    a           help for subcommand a
    b           help for subcommand b

A very cool program
 

Добавить

 parser_a = subparsers.add_parser("a", help='help for subcommand a')
 

Это также работает с вашей справочной группой.

===

add_parser Метод особым образом обрабатывает ключевое слово «help». «add_help» передается в функцию ArgumentParser создания. У них очень разные функции.

 def add_parser(self, name, **kwargs):
    # set prog from the existing prefix
    if kwargs.get('prog') is None:
        kwargs['prog'] = '%s %s' % (self._prog_prefix, name)

    aliases = kwargs.pop('aliases', ())

    # create a pseudo-action to hold the choice help
    if 'help' in kwargs:
        help = kwargs.pop('help')
        choice_action = self._ChoicesPseudoAction(name, aliases, help)
        self._choices_actions.append(choice_action)

    # create the parser and add it to the map
    parser = self._parser_class(**kwargs)
    self._name_parser_map[name] = parser

    # make parser available under aliases also
    for alias in aliases:
        self._name_parser_map[alias] = parser

    return parser
 

Комментарии:

1. Разница в том, что вы забыли добавить help="something" вместо того, чтобы просто удалить add_help=False from parser_a = subparsers.add_parser("a", add_help=False) . Если вы добавите help="something" диалоговое окно и удалите add_help=False его, вы увидите, что при использовании глобального -h вы получите то же самое сообщение справки, в данном случае «что-то», в разделе «Доступные подкоманды:». Возможно, мой запрос был не таким конкретным, как я думал.

2. add_help=False является параметром для самого subparser. Действие help='something' is used by the подпараторов.

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

4. Я не вижу этого «чего-то» в вашем диалоговом окне hlep подкоманды. Строка «справка для подкоманды a» не имеет никакого отношения к справке, отображаемой subpareser_a

5. Я использовал онлайн-компилятор, чтобы проиллюстрировать, что я имею в виду, перейдите к https://trinket.io/python3/d21a721232 и когда вы запустите скрипт, вы увидите, что справа от подкоманд есть диалоговое окно справки, в разделе «Доступные подкоманды:». Теперь попробуйте добавить диалоговое окно справки в подкомандах в свою собственную группу, закомментировав строки 24, 25, 37 и 38. Если вы снова запустите скрипт, он выдаст вам сообщение об ошибке. Это довольно сложно объяснить словами, поэтому, возможно, это делает то, чего я пытаюсь добиться, более понятным.