порядок параметров python argparse

#python #parameters #argparse

#python #параметры #argparse

Вопрос:

Есть ли какой-либо способ вручную упорядочить параметры с помощью модуля argparse?

На данный момент у меня есть это:

 usage: cons_test.py [-h] [-l L] [-R] [-O O] [-o O] [-T T] <STR_file> <PDB_file>
  

но я хотел бы иметь позиционные (и поэтому необязательные) параметры перед необязательными параметрами, например:

 usage: cons_test.py <STR_file> <PDB_file> [-h] [-l L] [-R] [-O O] [-o O] [-T T] 
  

Что я должен изменить в своем коде для достижения этого порядка?

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

1. Самый простой шаг, особенно для одноразового использования, — это написать свою собственную usage строку.

Ответ №1:

Вариант решения Martijn Pieters — удалите все перенос строк и отобразите аргументы в том порядке, в котором они определены.

 class RawUsageHelpFormatter(argparse.HelpFormatter):
    def _format_usage(self, usage, actions, groups, prefix):
        # use actions in the order that they are define
        # no line wrapping
        if prefix is None:
            prefix = 'usage: '
        if usage is not None:
            usage = usage % dict(prog=self._prog)
        elif usage is None and not actions:
            usage = '%(prog)s' % dict(prog=self._prog)
        elif usage is None:
            prog = '%(prog)s' % dict(prog=self._prog)
            format = self._format_actions_usage
            action_usage = format(actions, groups)
            usage = ' '.join([s for s in [prog, action_usage] if s])
        return '%s%snn' % (prefix, usage)
  

пример вывода:

 usage: stack24221824.py [-h] <STR_file> [-t T] <PDB_file> [-l {txt,html,pdf}] [-R] [-O {txt,html,pdf}]
  

[-h] является первым, потому что анализатор создает это сразу. Затем я определил STR , -t , PDB , и т.д. При необходимости, я думаю, вы могли бы подавить справку add_help=True и позже определить свой собственный -h аргумент. Если вы хотите перенос строки, вам нужно беспокоиться о том, где разрешено разбивать строку, и об отступах для последующих строк.

Ответ №2:

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

Следующий класс будет работать в Python 2 и 3, поскольку переопределенный метод по-прежнему вызывается таким же образом, но только для подгонки текста по ширине терминала (с использованием COLUMNS переменной среды, по умолчанию 80 столбцов минус 2 символа заполнения):

 class SwappedOrderHelpFormatter(argparse.HelpFormatter):
    def _format_actions_usage(self, actions, groups):
        # split optionals from positionals
        optionals = []
        positionals = []
        for action in actions:
            if action.option_strings:
                optionals.append(action)
            else:
                positionals.append(action)
        return super(SwappedOrderHelpFormatter, self)._format_actions_usage(
            positionals   optionals, groups)
  

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

 parser = argparse.ArgumentParser(
    # ....
    formatter_class=SwappedOrderHelpFormatter,
    # ....
    )
  

Если ваш текст не будет соответствовать ширине большинства терминалов, вам необходимо полностью переопределить argparse.HelpFormatter._format_usage() метод и поменять порядок переменных optionals and positionals .

ДЕМОНСТРАЦИЯ:

 >>> parser = argparse.ArgumentParser(prog='PROG', formatter_class=SwappedOrderHelpFormatter)
>>> parser.add_argument('-l', action='store_true')
_StoreTrueAction(option_strings=['-l'], dest='l', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('-R')
_StoreAction(option_strings=['-R'], dest='R', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('STR_file')
_StoreAction(option_strings=[], dest='STR_file', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('PDB_file')
_StoreAction(option_strings=[], dest='PDB_file', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.print_help()
usage: PROG STR_file PDB_file [-h] [-l] [-R R]

positional arguments:
  STR_file
  PDB_file

optional arguments:
  -h, --help  show this help message and exit
  -l
  -R R
  

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

1. Я полагаю, вам придется внести дополнительные изменения для обработки длинного многострочного использования.

2. @hpaulj: а, я понимаю, что ты имеешь в виду. if len(prefix) len(usage) > text_width: затем позиционные значения форматируются отдельно от дополнительных.

3. Этот _format_usage метод является хрупким. Он возвращает строку из _format_actions_usage , и пытается разделить ее на actions group единицы и, а затем объединить их обратно в строки. Мой патч в bugs.python.org/issue11874 является переписыванием этих методов.

4. @hpaulj: На самом деле весь HelpFormatter класс довольно хрупкий.

5. В отдельном скрипте ваш код работает, но как только я добавляю новый аргумент, а именно parser.add_argument("-O", "--output_file_name", choices=["txt", "html"], default="txt|html", help="output file name") порядок возвращается к нормальному: usage: SwappedOrder.py [-h] [-l {bic,pf1}] [-R] [-O {txt,html}] STR_file PDB_file что заставляет некоторые аргументы работать, а некоторые нет? Я пропускаю параметр аргумента am?