Настроить справочное сообщение argparse

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

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--version', action='version',
                    version='%(prog)s 1.0')
parser.parse_args()

В результате появляется следующее справочное сообщение.

$ python foo.py --help
usage: foo.py [-h] [-v]

optional arguments:
  -h, --help     show this help message and exit
  -v, --version  show program version number and exit

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

$ python foo.py --help
Usage: foo.py [-h] [-v]

Optional arguments:
  -h, --help     Show this help message and exit.
  -v, --version  Show program version number and exit.

Это что-то, что я могу контролировать, используя API-интерфейс argparse. Если да, то как? Не могли бы вы привести небольшой пример, который показывает, как это можно сделать?

Ответы

Ответ 1

Прежде всего: заглавная эти фразы летит перед лицом соглашения, а argparse не очень помогает вам легко изменить эти строки. Здесь у вас есть три разных класса строк: текст шаблона из форматирования справки, заголовки разделов и текст справки по конкретному варианту. Все эти строки являются локализуемыми; вы можете просто предоставить "капитализированный" перевод для всех этих строк с помощью поддержки gettext(). Тем не менее, вы можете достичь и заменить все эти строки, если вы достаточно уверены, и немного прочитать исходный код.

Действие version включает в себя текст по умолчанию help, но вы можете указать свой собственный, установив аргумент help. То же самое относится к действию help; если вы установите параметр add_help в False, вы можете добавить это действие вручную:

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-v', '--version', action='version',
                    version='%(prog)s 1.0', help="Show program version number and exit.")
parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
                    help='Show this help message and exit.')

Затем сообщение optional arguments является заголовком группы; каждый анализатор имеет две группы по умолчанию, одну для позиционных аргументов, другую для необязательной. Вы можете достигнуть их атрибутами _positionals и _optionals, оба из которых имеют атрибут title:

parser._positionals.title = 'Positional arguments'
parser._optionals.title = 'Optional arguments'

Будьте предупреждены, обратившись к именам, начинающимся с подчеркивания, вы отправляетесь в недокументированный частный API модуля, и ваш код может ломаться в будущих обновлениях.

Наконец, чтобы изменить строку usage, вам придется подклассифицировать формулятор справки; передать подкласс в качестве formatter_class аргумент:

class CapitalisedHelpFormatter(argparse.HelpFormatter):
    def add_usage(self, usage, actions, groups, prefix=None):
        if prefix is None:
            prefix = 'Usage: '
        return super(CapitalisedHelpFormatter, self).add_usage(
            usage, actions, groups, prefix)

parser = argparse.ArgumentParser(formatter_class=CapitalisedHelpFormatter)

Демонстрация, соединяя все это:

>>> import argparse
>>> class CapitalisedHelpFormatter(argparse.HelpFormatter):
...     def add_usage(self, usage, actions, groups, prefix=None):
...         if prefix is None:
...             prefix = 'Usage: '
...         return super(CapitalisedHelpFormatter, self).add_usage(
...             usage, actions, groups, prefix)
...
>>> parser = argparse.ArgumentParser(add_help=False, formatter_class=CapitalisedHelpFormatter)
>>> parser._positionals.title = 'Positional arguments'
>>> parser._optionals.title = 'Optional arguments'
>>> parser.add_argument('-v', '--version', action='version',
...                     version='%(prog)s 1.0', help="Show program version number and exit.")
_VersionAction(option_strings=['-v', '--version'], dest='version', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help="Show program version number and exit.", metavar=None)
>>> parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
...                     help='Show this help message and exit.')
_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='Show this help message and exit.', metavar=None)
>>> print(parser.format_help())
Usage: [-v] [-h]

Optional arguments:
  -v, --version  Show program version number and exit.
  -h, --help     Show this help message and exit.

Ответ 2

Martijn дал пару исправлений, которые приходили на ум - предоставляя параметр help и пользовательский класс Formatter.

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

Позвольте мне проиллюстрировать, для простого анализатора с помощью справки по умолчанию и другого аргумента список действий:

In [1064]: parser._actions
Out[1064]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]

Я могу просмотреть и изменить атрибут help любого из них:

In [1065]: parser._actions[0].help
Out[1065]: 'show this help message and exit'
In [1066]: parser._actions[0].help='Show this help message and exit.'

создавая эту помощь:

In [1067]: parser.parse_args(['-h'])
usage: ipython3 [-h] [-f FOO]    
optional arguments:
  -h, --help         Show this help message and exit.
  -f FOO, --foo FOO

Использование списка parser._actions использует атрибут 'private', который некоторые считают неразумным. Но в Python публичное/частное разграничение не является жестким и может быть нарушено с осторожностью. Martijn делает это, обращаясь к parser._positionals.title.

Другой способ изменения названия этой группы состоит в создании групп настраиваемых аргументов

ogroup=parser.add_argument_group('Correct Optionals Title')
ogroup.add_argument('-v',...)
ogroup.add_argument('-h',...)