Python argparse: увеличить расстояние между параметром и описанием - PullRequest
0 голосов
/ 02 октября 2018

Я использую Python3 argparse для сложного интерфейса командной строки.Множество аргументов, некоторые из которых являются «многословными», чтобы избежать недоразумений.

parser = argparse.ArgumentParser(description='Command-line interface')
parser.add_argument('--long-param-one',
                    help='Long param one description',
                    dest='lond_param_one',
                    required=True)

parser.add_argument('--long-param-two',
                    help='Long param two description',
                    dest='lond_param_two',
                    required=True)

Когда имя параметра достаточно длинное и целевая переменная также длинная, это вызывает уродливое форматирование при вызове скрипта с --help

Command-line interface

optional arguments:
  -h, --help            show this help message and exit
  --long-param-one LONG_PARAM_ONE
                        Long param one description
  --long-param-two LONG_PARAM_TWO
                        Long param two description

Я имею в виду, что параметр и значение находятся в одной строке, а описание - в другой, даже если на консоли справа достаточно места, чтобы поместить его в одну строку.Как и первый параметр --help.Когда у вас есть 30-40 параметров, читаемость справки командной строки действительно ухудшается

Ответы [ 2 ]

0 голосов
/ 02 октября 2018

Текущий HelpFormatter проверяет os.environ['COLUMNS'] ширину терминала.Но это не обновляется динамически и может даже не быть установлено.

Существует патч

https://bugs.python.org/file24602/issue13041.patch argparse: terminal width is not detected properly

, который, по-видимому, был недавнов 3.8, вместо этого shutil.get_terminal_size().columns.


Почему argparse не обеспечивает более прямой контроль этой ширины - философия дизайна допускает пользовательскую спецификацию formatter_class, а не (потенциально) большой набор параметров форматирования.Большинство параметров ArgumentParser имеют отношение к синтаксическому анализу, а не к форматированию.Цель состоит в том, чтобы позволить полную настройку, не загромождая входные данные множеством редко используемых параметров.

Класс HelpFormatter принимает несколько ключевых параметров:

HelpFormatter.__init__(self, prog, indent_increment=2, max_help_position=24, width=None)

Но текущий методсоздание форматера просто передает параметр prog.

Ответ Джакомо показывает, как задать эти другие параметры:

formatter = lambda prog: argparse.HelpFormatter(prog,max_help_position=52)

Вы также можете создать подкласс HelpFormatter для настройки форматирования.Вот что делают альтернативы, такие как RawTextHelpFormatter.

Подробнее о настройке форматера

Из документации argparse:

formatter_class

ArgumentParser объектыПозволяет настроить форматирование справки, указав альтернативный класс форматирования.В настоящее время существует четыре таких класса:

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

В https://bugs.python.org/issue13023, Стивен Бетхард, первоначальный автор argparse, рекомендует написать свой собственный класс форматирования:

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

Микширование, о котором он говорит, это:

class myFormatter(argparse.RawDescriptionHelpFormatter,
                  argparse.ArgumentDefaultsHelpFormatter):
    pass

Я говорил об использовании max_help_position 3 года назад:

https://bugs.python.org/issue25297 max_help_position is not works in argparse library

и вопрос SO:

max_help_position не работает в библиотеке python argparse

Другие примеры в argparse, где вам разрешено предоставлять пользовательские классы или функции, включают:

https://docs.python.org/3/library/argparse.html#action-classes https://docs.python.org/3/library/argparse.html#the-namespace-object https://docs.python.org/3/library/argparse.html#customizing-file-parsing https://docs.python.org/3/library/argparse.html#type

Я бы не беспокоился об исчезновении или отключении параметра max_help_position.Если у меня есть какое-либо мнение по этому вопросу, любое предложенное изменение, подобное этому, будет отклонено на том основании, что оно может иметь проблемы с обратной совместимостью.

На практике проще всего изменить документацию для соответствия коду или для улучшенияпроиллюстрировать смутные моменты.В этом случае lambda вызов HelpFormatter может быть задокументирован.Я также могу представить определение маленькой функции, которая делает то же самое.Добавление функций проще всего, когда нет шансов навредить существующим пользователям.

0 голосов
/ 02 октября 2018

argparse по умолчанию ограничивает максимальное пространство, занимаемое для опции + metavar, и выводит справочное сообщение в отдельной строке, даже если терминал будет достаточно большим, чтобы вместить оба.

Рассмотрим этот примерscript:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--name', help='help help')
parser.add_argument('--parameter', help='help help')
parser.add_argument('--parameter-name', help='help help')
parser.add_argument('--this-parameter-name', help='help help')
parser.add_argument('--this-is-parameter-name', help='help help')
parser.add_argument('--this-is-a-parameter-name', help='help help')
parser.add_argument('--this-is-a-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help')
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help')

parser.parse_args()

В результате получается следующий вывод:

usage: a.py [-h] [--name NAME] [--parameter PARAMETER]
            [--parameter-name PARAMETER_NAME]
            [--this-parameter-name THIS_PARAMETER_NAME]
            [--this-is-parameter-name THIS_IS_PARAMETER_NAME]
            [--this-is-a-parameter-name THIS_IS_A_PARAMETER_NAME]
            [--this-is-a-long-parameter-name THIS_IS_A_LONG_PARAMETER_NAME]
            [--this-is-a-very-long-parameter-name THIS_IS_A_VERY_LONG_PARAMETER_NAME]
            [--this-is-a-very-very-long-parameter-name THIS_IS_A_VERY_VERY_LONG_PARAMETER_NAME]
            [--this-is-a-very-very-very-long-parameter-name THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME]

optional arguments:
  -h, --help            show this help message and exit
  --name NAME           help help
  --parameter PARAMETER
                        help help
  --parameter-name PARAMETER_NAME
                        help help
  --this-parameter-name THIS_PARAMETER_NAME
                        help help
  --this-is-parameter-name THIS_IS_PARAMETER_NAME
                        help help
  --this-is-a-parameter-name THIS_IS_A_PARAMETER_NAME
                        help help
  --this-is-a-long-parameter-name THIS_IS_A_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-long-parameter-name THIS_IS_A_VERY_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-very-long-parameter-name THIS_IS_A_VERY_VERY_LONG_PARAMETER_NAME
                        help help
  --this-is-a-very-very-very-long-parameter-name THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME
                        help help

Самый простой способ попробовать , чтобы избежать этой проблемы, - явно указать metavar и использоватькороткое значение, поэтому вместо THIS_IS_A_VERY_VERY_VERY_LONG_PARAMETER_NAME вы можете использовать, скажем, X.Например:

import argparse

parser = argparse.ArgumentParser()
m = 'X'
parser.add_argument('--name', help='help help', metavar=m)
parser.add_argument('--parameter', help='help help', metavar=m)
parser.add_argument('--parameter-name', help='help help', metavar=m)
parser.add_argument('--this-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help', metavar=m)

parser.parse_args()

Что приводит к:

usage: a.py [-h] [--name X] [--parameter X] [--parameter-name X]
            [--this-parameter-name X] [--this-is-parameter-name X]
            [--this-is-a-parameter-name X] [--this-is-a-long-parameter-name X]
            [--this-is-a-very-long-parameter-name X]
            [--this-is-a-very-very-long-parameter-name X]
            [--this-is-a-very-very-very-long-parameter-name X]

optional arguments:
  -h, --help            show this help message and exit
  --name X              help help
  --parameter X         help help
  --parameter-name X    help help
  --this-parameter-name X
                        help help
  --this-is-parameter-name X
                        help help
  --this-is-a-parameter-name X
                        help help
  --this-is-a-long-parameter-name X
                        help help
  --this-is-a-very-long-parameter-name X
                        help help
  --this-is-a-very-very-long-parameter-name X
                        help help
  --this-is-a-very-very-very-long-parameter-name X
                        help help

это уже намного лучше, но, как вы можете видеть с очень длинными именами параметров, он все равно не будет записывать весь текст на одномline.

Единственный способ добиться желаемого - указать formatter_class и использовать max_help_position, как описано в этого вопроса .Это, однако, не является частью общедоступного API модуля.Я понятия не имею, когда они не добавили хотя бы пару полезных параметров в публичный API.

Вы все еще, вероятно, захотите указать metavar:

import argparse

formatter = lambda prog: argparse.HelpFormatter(prog,max_help_position=52)
parser = argparse.ArgumentParser(formatter_class=formatter)
m = 'X'
parser.add_argument('--name', help='help help', metavar=m)
parser.add_argument('--parameter', help='help help', metavar=m)
parser.add_argument('--parameter-name', help='help help', metavar=m)
parser.add_argument('--this-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-long-parameter-name', help='help help', metavar=m)
parser.add_argument('--this-is-a-very-very-very-long-parameter-name', help='help help', metavar=m)

parser.parse_args()

Вывод будетбыть:

usage: a.py [-h] [--name X] [--parameter X] [--parameter-name X]
            [--this-parameter-name X] [--this-is-parameter-name X]
            [--this-is-a-parameter-name X] [--this-is-a-long-parameter-name X]
            [--this-is-a-very-long-parameter-name X]
            [--this-is-a-very-very-long-parameter-name X]
            [--this-is-a-very-very-very-long-parameter-name X]

optional arguments:
  -h, --help                                        show this help message and
                                                    exit
  --name X                                          help help
  --parameter X                                     help help
  --parameter-name X                                help help
  --this-parameter-name X                           help help
  --this-is-parameter-name X                        help help
  --this-is-a-parameter-name X                      help help
  --this-is-a-long-parameter-name X                 help help
  --this-is-a-very-long-parameter-name X            help help
  --this-is-a-very-very-long-parameter-name X       help help
  --this-is-a-very-very-very-long-parameter-name X  help help

Возможно, вы можете попытаться определить размер терминала (большинство терминалов предоставляют переменную WIDTH или COLUMNS env, которая может быть полезна для этого), чтобы определить значение max_help_position это было бы лучше всего в этой ситуации.


Чтобы все параметры помогали в одной строке (при условии достаточно большого терминала), вы хотите:

max_help_position >= max(len(param.name)+len(param.metavar) for param in params)
...