Сортировка справочной информации по алфавиту
Я использую средство 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 в алфавитном порядке добавления, но я стараюсь избегать этого.
Ответы
Ответ 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
, которые относительно просты и высоки.