Сортировка справочной информации по алфавиту - программирование

Сортировка справочной информации по алфавиту

Я использую средство argparse Python (2.7) и хотел бы автоматически сортировать помощь, которую он производит по алфавиту по опции.

По умолчанию записи справки сортируются в том порядке, в котором они добавлены *, как в:

p = argparse.ArgumentParser(description='Load duration curves and other plots')
p.add_argument('--first', '-f', type=int, default=1, help='First Hour')
p.add_argument('--dur', '-d', type=int, default=-1, help='Duration in Hours. Use -1 for all')
p.add_argument('--title', '-t', help='Plot Title (for all plots), default=file name')
p.add_argument('--interp', '-i', action="store_true", default=True, 
                help='Use linear interpolation for smoother curves')
...
args = p.parse_args()

Что при вызове python script -h вызывает:

usage: script.py [-h] [--first FIRST] [--dur DUR] [--title TITLE] [--interp]

Load duration curves and other plots

optional arguments:
  -h, --help            show this help message and exit
  --first FIRST, -f FIRST
                        First Hour
  --dur DUR, -d DUR     Duration in Hours. Use -1 for all
  --title TITLE, -t TITLE
                        Plot Title (for all plots), default=file name
  --interp, -i          Use linear interpolation for smoother curves

Можно ли автоматически сортировать их в алфавитном порядке? Это будет dur, во-первых, h, interp, title.

* Очевидно, что работа вокруг заключается в ручном обслуживании путем добавления записей с использованием p.add_argument в алфавитном порядке добавления, но я стараюсь избегать этого.

4b9b3361

Ответ 1

Вы можете сделать это, предоставив собственный HelpFormatter класс; внутренности которых официально недокументированы. Это означает, что вы сами по себе, когда дело доходит до совместимости с версией Python до версии, но я считаю интерфейс довольно стабильным:

from argparse import HelpFormatter
from operator import attrgetter

class SortingHelpFormatter(HelpFormatter):
    def add_arguments(self, actions):
        actions = sorted(actions, key=attrgetter('option_strings'))
        super(SortingHelpFormatter, self).add_arguments(actions)


p = argparse.ArgumentParser(...
    formatter_class=SortingHelpFormatter,
)

Здесь я сортирую строки опций (('--dur', '-d') и т.д.), но вы можете выбрать, что вы хотите отсортировать. Эта простая опция сортировки ставит опции с одним типом в прошлом, например, параметр -h.

который выводит:

usage: [-h] [--first FIRST] [--dur DUR] [--title TITLE] [--interp]

Load duration curves and other plots

optional arguments:
  --dur DUR, -d DUR     Duration in Hours. Use -1 for all
  --first FIRST, -f FIRST
                        First Hour
  --interp, -i          Use linear interpolation for smoother curves
  --title TITLE, -t TITLE
                        Plot Title (for all plots), default=file name
  -h, --help            show this help message and exit

Ответ 2

Когда вы создаете класс ArgumentParser, вы можете передать в формате form: http://docs.python.org/library/argparse.html#formatter-class

По-видимому, вы можете использовать один из поставляемых форматировщиков, но не можете переопределить и заменить их без обратной инженерии:

>>> h = argparse.ArgumentDefaultsHelpFormatter
>>> print h.__doc__
Help message formatter which adds default values to argument help.

    Only the name of this class is considered a public API. All the methods
    provided by the class are considered an implementation detail.

Ответ 3

Альтернативный, определенно более уродливый способ сделать это, чем предлагал @MartijnPieters:

p = argparse.ArgumentParser()

#add arguements here

for g in p._action_groups:
    g._group_actions.sort(key=lambda x:x.dest)

Это может быть удобно помещать в предложение try/except, поскольку оно помогает только форматированию, поэтому для выполнения программы не должно иметь значения, если этот фрагмент кода завершился с ошибкой на AttributeError или что-то...

Ответ 4

Это похоже на ответ @mgilson. Я думал, что я опубликовал это раньше, но, по-видимому, нет.

d = dict()
d['--first'] = ('-f', "type=int", "default=1", "help='First Hour'")
d['--dur'] = ('-d', type=int, default=-1, help='Duration in Hours. Use -1 for all')
# etc

for prim_option in sorted(d):
    p.add_arguments(prim_option, *d[prim_option])

Вы можете настроить то, что именно используется в качестве ключа в словаре, а также аргументы sorted и точную структуру вызова add_arguments, чтобы получить желаемый порядок сортировки. Это относится к публично документированному интерфейсу argparse, но добавляет слой к процессу определения вашего синтаксического анализатора. (В зависимости от вашей философии такое разделение информации о параметрах от реализации парсера может быть хорошим.)

Ответ 5

Порядок аргументов в помощи определяется методом parser.format_help:

Definition:  parser.format_help(self)
Source:
    def format_help(self):
        formatter = self._get_formatter()
        ...
        # positionals, optionals and user-defined groups
        for action_group in self._action_groups:
            formatter.start_section(action_group.title)
            formatter.add_text(action_group.description)
            formatter.add_arguments(action_group._group_actions)
            formatter.end_section()

help создается путем извлечения объекта formatter, а затем добавления в него "разделов". Здесь он проходит через _action_groups, помещая каждый в свой раздел и добавляя его действия (аргументы) с помощью метода add_arguments. Форматирование является временным, существующим только для создания строк (обычно нескольких строк).

Группы действий включают по умолчанию postionals и optionals, а также любые созданные пользователем. Эти группы используются только для помощи, а не для синтаксического анализа. Таким образом, список action_group._group_actions можно переупорядочить, не влияя на разбор. (у парсера есть свой собственный список действий, parser._actions).

Это подтверждает наблюдение @mgilson, что сортировка p._actions не влияет на справку, но сортировка _group_actions делает.

Сортировка _actions будет влиять на usage (будь то часть справки или автономная):

    # usage
    formatter.add_usage(self.usage, self._actions,
                        self._mutually_exclusive_groups)

Обратите внимание, что action_groups не передаются в раздел использования. Раздел использования выполняет переопределение своих действий, сначала отображая optionals, затем positionals.

Сортировка аргументов до/во время этапа add_argument, если вы хотите управлять порядком разбора позиций и их порядком в использовании.

Если вы просто хотите контролировать порядок в группах справки, то можете свободно изменять порядок в списке ._group_actions либо перед вызовом форматирования, либо внутри него.

Были и другие SO вопросы об управлении порядком действий в usage. Некоторые, например, не хотят, чтобы positionals упорядочивался после optionals.

Я согласен, что класс Formatter является громоздким. Но это, по большей части, отдельно от класса Parser. Поэтому его можно было бы переписать с минимальным эффектом на разбор. Существующие подклассы Formatter просто настраивают методы низкого уровня, которые управляют оберткой строк и формированием строки справки. Значительным интерфейсом между парсером и форматированием являются методы format_usage и format_help, которые относительно просты и высоки.