Модульное справочное сообщение с помощью python argparse

#python #argparse

#питон #argparse

Вопрос:

Я использую python argparse для управления параметрами командной строки. Когда количество опций становится большим, справочное сообщение (то, что выводит argparse при передаче --help ) становится пугающим и трудным для чтения просто потому, что оно слишком длинное. Другие программы иногда решают эту проблему, модулируя справочное сообщение: они показывают только «основные параметры» --help и имеют такие параметры --help-modulea , как --help-moduleb , и т.д.

Я думаю, что argparse допускает нечто подобное при наличии подкоманд, по сути, как это делает git: ./script.py command --help . Однако в моем приложении нет такого понятия, как подкоманды, только большой набор опций (которые, однако, можно красиво сгруппировать).

Есть ли какой-нибудь (разумный) способ сделать это с помощью argparse?

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

1. Возможно, вы просто ищете группы аргументов , хотя они не помогают подавить часть выходных данных. Для этого вам нужно будет определить свои собственные обработчики параметров.

2. Я уже использую группы аргументов для группировки аргументов. (очевидно) Однако я не совсем понимаю, что вы подразумеваете под «обработчиками опций»…

3. Посмотрите на код для print_help и format_help . Вы увидите, как HelpFormatter вызывается объект и как ему передаются группы. Также посмотрите на _help_action класс (или какое-то подобное название). Я могу представить себе создание аналогичных подклассов действий и / или форматеров, которые отображают подмножество ваших argument_groups .

Ответ №1:

Благодаря ответу @hpaulj я должным образом изучил argparse внутренности и пришел к следующему. Хотя в нем есть некоторые оговорки, я считаю, что это хорошее начало:

 class ModularHelpEnabler(argparse.Action):
    def __call__(self, parser, namespace, values, option_string = None):
        parser.enable_modular_help(self.const)

class ModularArgumentParser(argparse.ArgumentParser):
    def __init__(self, *args, **kwargs):
        self._modular_action_groups = {}
        modular_help_groups = kwargs.pop('modular_help_groups', [])
        super().__init__(*args, **kwargs)
        self._modular_help_groups = {}
        for name in modular_help_groups:
            self._modular_help_groups[name] = self.add_argument_group(name)

    def add_argument_group(self, *args, **kwargs):
        name = kwargs.pop('help_name', None)
        help_group = kwargs.pop('help_group', None)
        help_text = kwargs.pop('help_group', 'show help for {}')
        grp = super().add_argument_group(*args, **kwargs)
        if name is not None:
            self._modular_action_groups[grp] = name
            parser = self
            if help_group is not None:
                parser = self._modular_help_groups[help_group]
            parser.add_argument('--help-{}'.format(name), action=ModularHelpEnabler, nargs=0, const=grp, help = help_text.format(name))
        return grp
    def enable_modular_help(self, grp):
        del self._modular_action_groups[grp]
    def format_help(self):
        self._action_groups = [
            ag for ag in self._action_groups
            if ag not in self._modular_action_groups
        ]
        return super().format_help()
 

Предостережения (которые нетривиально исправить, AFAIK):

  • --help-foo не подразумевает --help .
  • --help-foo необходимо указать раньше --help .

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