optparse — Парсер для опций командной строки

Исходный код: Lib/optparse.py.

Не рекомендуется, начиная с версии 3.2: Модуль optparse является устаревшим и не будет развиваться дальше; развитие будет продолжено с модулем argparse.


optparse - это более удобная, гибкая и мощная библиотека для разбора опций командной строки, чем старый модуль getopt. optparse использует более декларативный стиль разбора командной строки: вы создаете экземпляр OptionParser, заполняете его опциями и разбираете командную строку. optparse позволяет пользователям указывать опции в обычном синтаксисе GNU/POSIX и дополнительно генерирует для вас сообщения об использовании и справку.

Вот пример использования optparse в простом сценарии:

from optparse import OptionParser
...
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
                  help="write report to FILE", metavar="FILE")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose", default=True,
                  help="don't print status messages to stdout")

(options, args) = parser.parse_args()

С помощью этих нескольких строк кода пользователи вашего скрипта теперь могут делать «обычные вещи» в командной строке, например:

<yourscript> --file=outfile -q

По мере разбора командной строки optparse устанавливает атрибуты объекта options, возвращаемого parse_args(), на основе значений, введенных пользователем из командной строки. Когда parse_args() возвращается после разбора этой командной строки, options.filename будет "outfile", а options.verbose будет False. optparse поддерживает как длинные, так и короткие опции, позволяет объединять короткие опции вместе, а также позволяет связывать опции с их аргументами различными способами. Таким образом, все следующие командные строки эквивалентны приведенному выше примеру:

<yourscript> -f outfile --quiet
<yourscript> --quiet --file outfile
<yourscript> -q -foutfile
<yourscript> -qfoutfile

Кроме того, пользователи могут выполнить один из следующих пунктов:

<yourscript> -h
<yourscript> --help

и optparse выведут краткую информацию о параметрах вашего сценария:

Usage: <yourscript> [options]

Options:
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  write report to FILE
  -q, --quiet           don't print status messages to stdout

где значение yourscript определяется во время выполнения (обычно из sys.argv[0]).

Справочная информация

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

Терминология

аргумент

строка, введенная в командной строке и переданная оболочкой в execl() или execv(). В Python аргументы - это элементы sys.argv[1:] (sys.argv[0] - это имя выполняемой программы). В оболочках Unix также используется термин «слово».

Иногда желательно подставить список аргументов, отличный от sys.argv[1:], поэтому следует читать «аргумент» как «элемент sys.argv[1:] или другого списка, предоставляемого в качестве замены sys.argv[1:]».

вариант

аргумент, используемый для предоставления дополнительной информации, чтобы направлять или настраивать выполнение программы. Существует множество различных синтаксисов для опций; традиционный синтаксис Unix - это дефис («-«), за которым следует одна буква, например, -x или -F. Кроме того, традиционный синтаксис Unix позволяет объединять несколько опций в один аргумент, например, -x -F эквивалентен -xF. Проект GNU ввел --, за которым следует серия слов, разделенных дефисом, например --file или --dry-run. Это единственные два синтаксиса опций, предоставляемых optparse.

Некоторые другие синтаксисы опций, которые видел мир, включают:

  • дефис, за которым следует несколько букв, например, -pf (это не то же самое, что несколько вариантов, объединенных в один аргумент)

  • дефис, за которым следует целое слово, например, -file (технически это эквивалентно предыдущему синтаксису, но обычно они не встречаются в одной программе)

  • знак плюс, за которым следует одна буква, или несколько букв, или слово, например, +f, +rgb

  • косая черта, за которой следует буква, или несколько букв, или слово, например, /f, /file

Эти синтаксисы опций не поддерживаются optparse и никогда не будут поддерживаться. Это сделано намеренно: первые три нестандартны для любой среды, а последний имеет смысл только в том случае, если вы ориентируетесь исключительно на Windows или некоторые старые платформы (например, VMS, MS-DOS).

аргумент опции

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

-f foo
--file foo

или включены в один аргумент:

-ffoo
--file=foo

Обычно опция либо принимает аргумент, либо нет. Многие люди хотят иметь функцию «необязательных аргументов опции», то есть некоторые опции будут принимать аргумент, если видят его, и не будут, если не видят. Это несколько противоречиво, потому что делает разбор неоднозначным: если -a принимает необязательный аргумент, а -b - это совсем другая опция, как нам интерпретировать -ab? Из-за этой неоднозначности optparse не поддерживает эту возможность.

позиционный аргумент

что-то оставшееся в списке аргументов после разбора опций, то есть после того, как опции и их аргументы были разобраны и удалены из списка аргументов.

необходимая опция

опция, которая должна быть задана в командной строке; обратите внимание, что фраза «требуемая опция» является самопротиворечивой в английском языке. optparse не мешает вам реализовать требуемые опции, но и не сильно помогает вам в этом.

Например, рассмотрим эту гипотетическую командную строку:

prog -v --report report.txt foo bar

-v и --report являются опциями. Если предположить, что --report принимает один аргумент, то report.txt является аргументом опции. foo и bar являются позиционными аргументами.

Для чего нужны опционы?

Опции используются для предоставления дополнительной информации, чтобы настроить или адаптировать выполнение программы. Если вы не поняли, опции обычно являются опциональными. Программа должна работать нормально без каких-либо опций. (Выберите произвольную программу из наборов инструментов Unix или GNU. Может ли она работать без каких-либо опций вообще и сохранять смысл? Основными исключениями являются find, tar и dd- все они являются мутантами, которые справедливо критиковались за их нестандартный синтаксис и запутанный интерфейс).

Многие люди хотят, чтобы в их программах были «обязательные опции». Подумайте об этом. Если это обязательно, то это не опционально! Если есть часть информации, которая абсолютно необходима вашей программе для успешного выполнения, то для этого и нужны позиционные аргументы.

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

cp SOURCE DEST
cp SOURCE ... DEST-DIR

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

Для чего нужны позиционные аргументы?

Позиционные аргументы предназначены для тех частей информации, которые абсолютно, позитивно необходимы вашей программе для выполнения.

Хороший пользовательский интерфейс должен иметь как можно меньше абсолютных требований. Если для успешного запуска вашей программы требуется 17 отдельных частей информации, не имеет особого значения, каким образом* вы получите эту информацию от пользователя - большинство людей сдадутся и уйдут, прежде чем успешно запустят программу. Это относится к интерфейсу пользователя, будь то командная строка, конфигурационный файл или графический интерфейс: если вы предъявляете столько требований к пользователям, большинство из них просто сдадутся.

Короче говоря, постарайтесь свести к минимуму количество информации, которую пользователи должны предоставлять в обязательном порядке - используйте разумные значения по умолчанию, когда это возможно. Конечно, вы также хотите сделать свои программы достаточно гибкими. Для этого и существуют опции. Опять же, неважно, будут ли это записи в конфигурационном файле, виджеты в диалоге «Preferences» графического интерфейса или опции командной строки - чем больше опций вы реализуете, тем более гибкой будет ваша программа, и тем сложнее станет ее реализация. Слишком большая гибкость, конечно, имеет и недостатки; слишком большое количество опций может перегрузить пользователей и сделать ваш код гораздо более сложным для сопровождения.

Учебник

Хотя optparse является довольно гибким и мощным, в большинстве случаев он также прост в использовании. В этом разделе рассматриваются шаблоны кода, которые являются общими для любой программы, основанной на optparse.

Сначала нужно импортировать класс OptionParser; затем в начале основной программы создать экземпляр OptionParser:

from optparse import OptionParser
...
parser = OptionParser()

Затем можно приступить к определению опций. Основной синтаксис следующий:

parser.add_option(opt_str, ...,
                  attr=value, ...)

Каждая опция имеет одну или несколько строк опций, например -f или --file, и несколько атрибутов опций, которые говорят optparse, что ожидать и что делать, когда он встречает эту опцию в командной строке.

Как правило, каждая опция имеет одну короткую строку опции и одну длинную строку опции, например:

parser.add_option("-f", "--file", ...)

Каждая опция имеет одну или несколько строк опций, например или , и несколько атрибутов опций, которые говорят , что ожидать и что делать, когда он встречает эту опцию в командной строке.

Строки опций, переданные в OptionParser.add_option(), фактически являются метками для опции, определенной этим вызовом. Для краткости мы будем часто ссылаться на встречу опции в командной строке; в действительности optparse встречает строки опций и ищет опции из них.

Когда все опции определены, дайте команду optparse разобрать командную строку вашей программы:

(options, args) = parser.parse_args()

(Если хотите, вы можете передать пользовательский список аргументов в parse_args(), но это редко необходимо: по умолчанию он использует sys.argv[1:]).

parse_args() возвращает два значения:

  • options, объект, содержащий значения для всех ваших опций - например, если --file принимает единственный строковый аргумент, то options.file будет именем файла, предоставленным пользователем, или None, если пользователь не предоставил эту опцию

  • args, список позиционных аргументов, оставшихся после разбора опций

В этом учебном разделе рассматриваются только четыре наиболее важных атрибута опций: action, type, dest (назначение) и help. Из них action является наиболее фундаментальным.

Понимание действий опционов

Действия указывают optparse, что делать, когда он встречает опцию в командной строке. Существует фиксированный набор действий, жестко закодированный в optparse; добавление новых действий - это продвинутая тема, рассматриваемая в разделе Расширение optparse. Большинство действий указывают optparse сохранить значение в некоторой переменной - например, взять строку из командной строки и сохранить ее в атрибуте options.

Если вы не указали действие опции, optparse по умолчанию принимает значение store.

Действие магазина

Наиболее распространенным действием опции является store, которое говорит optparse взять следующий аргумент (или остаток текущего аргумента), убедиться, что он правильного типа, и сохранить его в выбранном вами месте назначения.

Например:

parser.add_option("-f", "--file",
                  action="store", type="string", dest="filename")

Теперь давайте составим фальшивую командную строку и попросим optparse разобрать ее:

args = ["-f", "foo.txt"]
(options, args) = parser.parse_args(args)

Когда optparse видит строку опций -f, он потребляет следующий аргумент, foo.txt, и сохраняет его в options.filename. Таким образом, после этого вызова parse_args(), options.filename становится "foo.txt".

Некоторые другие типы опций, поддерживаемые optparse, это int и float. Вот опция, которая ожидает целочисленный аргумент:

parser.add_option("-n", type="int", dest="num")

Обратите внимание, что у этой опции нет длинной строки опции, что вполне допустимо. Также нет явного действия, поскольку по умолчанию стоит store.

Давайте разберем еще одну поддельную командную строку. На этот раз мы засунем аргумент опции прямо против опции: поскольку -n42 (один аргумент) эквивалентен -n 42 (два аргумента), код

(options, args) = parser.parse_args(["-n42"])
print(options.num)

выведет 42.

Если тип не указан, optparse предполагает string. В сочетании с тем, что действие по умолчанию store, это означает, что наш первый пример может быть намного короче:

parser.add_option("-f", "--file", dest="filename")

Если вы не указали место назначения, optparse вычисляет разумное значение по умолчанию из строк опций: если первая длинная строка опций --foo-bar, то местом назначения по умолчанию будет foo_bar. Если длинных строк опций нет, optparse рассматривает первую короткую строку опций: пункт назначения по умолчанию для -f - f.

optparse также включает встроенный тип complex. Добавление типов рассматривается в разделе Расширение optparse.

Обработка булевых (флаговых) опций

Опции флагов - установка переменной в true или false при появлении определенной опции - довольно распространены. optparse поддерживает их с помощью двух отдельных действий, store_true и store_false. Например, у вас может быть флаг verbose, который включается с помощью -v и выключается с помощью -q:

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose")

Здесь у нас есть два разных варианта с одинаковым назначением, что совершенно нормально. (Это просто означает, что вы должны быть немного осторожны при установке значений по умолчанию - см. ниже).

Когда optparse встречает -v в командной строке, он устанавливает options.verbose в True; когда он встречает -q, options.verbose устанавливается в False.

Другие действия

Некоторые другие действия, поддерживаемые optparse, следующие:

"store_const"

хранить постоянное значение

"append"

добавить аргумент этой опции в список

"count"

увеличить счетчик на единицу

"callback"

вызов указанной функции

Они рассматриваются в разделе Справочное руководство и в разделе Обратные вызовы опций.

Значения по умолчанию

Все приведенные выше примеры подразумевают установку некоторой переменной («назначения») при появлении определенных опций командной строки. Что произойдет, если эти опции никогда не появятся? Поскольку мы не задали никаких значений по умолчанию, все они будут установлены в None. Обычно это нормально, но иногда хочется большего контроля. optparse позволяет задать значение по умолчанию для каждого пункта назначения, которое присваивается до разбора командной строки.

Сначала рассмотрим пример verbose/quiet. Если мы хотим, чтобы optparse устанавливал verbose в True, пока не появится -q, то мы можем сделать следующее:

parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose")

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

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose", default=True)

Подумайте вот о чем:

parser.add_option("-v", action="store_true", dest="verbose", default=False)
parser.add_option("-q", action="store_false", dest="verbose", default=True)

Опять же, значение по умолчанию для verbose будет True: последнее значение по умолчанию, предоставленное для любого конкретного назначения, является тем, которое имеет значение.

Более понятным способом задания значений по умолчанию является метод set_defaults() OptionParser, который вы можете вызвать в любое время перед вызовом parse_args():

parser.set_defaults(verbose=True)
parser.add_option(...)
(options, args) = parser.parse_args()

Как и раньше, последнее значение, указанное для данного пункта назначения опции, является значением по умолчанию. Для ясности старайтесь использовать один или другой метод установки значений по умолчанию, а не оба.

Генерация помощи

Способность optparse автоматически генерировать справку и текст использования полезна для создания дружественных интерфейсов командной строки. Все, что вам нужно сделать, это указать значение help для каждой опции и, по желанию, краткое сообщение об использовании всей вашей программы. Вот OptionParser, заполненный удобными для пользователя (документированными) опциями:

usage = "usage: %prog [options] arg1 arg2"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", default=True,
                  help="make lots of noise [default]")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose",
                  help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
                  metavar="FILE", help="write output to FILE")
parser.add_option("-m", "--mode",
                  default="intermediate",
                  help="interaction mode: novice, intermediate, "
                       "or expert [default: %default]")

Если optparse встречает -h или --help в командной строке, или если вы просто вызываете parser.print_help(), он печатает следующее на стандартный вывод:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

(Если вывод справки вызван опцией help, optparse завершается после печати текста справки).

Здесь многое делается для того, чтобы помочь optparse сформировать наилучшее возможное сообщение о помощи:

  • сценарий определяет свое собственное сообщение об использовании:

    usage = "usage: %prog [options] arg1 arg2"
    

    optparse расширяет %prog в строке использования до имени текущей программы, т.е. os.path.basename(sys.argv[0]). Расширенная строка выводится перед подробной справкой по опциям.

    Если вы не предоставите строку использования, optparse будет использован простой, но разумный вариант по умолчанию: "Usage: %prog [options]", что хорошо, если ваш скрипт не принимает никаких позиционных аргументов.

  • Каждая опция определяет строку справки и не заботится об обертывании строк -optparse позаботится об обертывании строк и приведении справки в надлежащий вид.

  • Опции, принимающие значение, указывают на этот факт в автоматически создаваемом справочном сообщении, например, для опции «mode»:

    -m MODE, --mode=MODE
    

    Здесь «MODE» называется мета-переменной: она обозначает аргумент, который пользователь должен передать в -m/--mode. По умолчанию optparse преобразует имя целевой переменной в верхний регистр и использует его для мета-переменной. Иногда это не то, что вам нужно - например, опция --filename явно устанавливает metavar="FILE", в результате чего автоматически создается следующее описание опции:

    -f FILE, --filename=FILE
    

    Однако это важно не только для экономии места: в написанном вручную тексте справки мета-переменная FILE используется для подсказки пользователю, что существует связь между полуформальным синтаксисом -f FILE и неформальным семантическим описанием «записать вывод в FILE». Это простой, но эффективный способ сделать текст справки намного понятнее и полезнее для конечных пользователей.

  • опции, имеющие значение по умолчанию, могут включать %default в строку справки—optparse заменит его на str() значение по умолчанию опции. Если опция не имеет значения по умолчанию (или значение по умолчанию равно None), %default расширяется до none.

Параметры группировки

При работе с большим количеством опций удобно группировать эти опции для лучшего вывода справки. Параметр OptionParser может содержать несколько групп опций, каждая из которых может содержать несколько опций.

Группа опций получается с помощью класса OptionGroup:

class optparse.OptionGroup(parser, title, description=None)

где

  • парсер является экземпляром OptionParser, в который будет вставлена группа, чтобы

  • title - название группы

  • описание, необязательное, представляет собой длинное описание группы

OptionGroup наследуется от OptionContainer (как и OptionParser) и поэтому метод add_option() может быть использован для добавления опции в группу.

После объявления всех опций с помощью метода OptionParser add_option_group() группа добавляется к ранее определенному парсеру.

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

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

Это приведет к следующему выводу справки:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

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

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

group = OptionGroup(parser, "Debug Options")
group.add_option("-d", "--debug", action="store_true",
                 help="Print debug information")
group.add_option("-s", "--sql", action="store_true",
                 help="Print all SQL statements executed")
group.add_option("-e", action="store_true", help="Print every action done")
parser.add_option_group(group)

что приводит к следующему результату:

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or expert
                        [default: intermediate]

  Dangerous Options:
    Caution: use these options at your own risk.  It is believed that some
    of them bite.

    -g                  Group option.

  Debug Options:
    -d, --debug         Print debug information
    -s, --sql           Print all SQL statements executed
    -e                  Print every action done

Еще один интересный метод, в частности, при программной работе с группами опций:

OptionParser.get_option_group(opt_str)

Возвращает OptionGroup, к которому принадлежит короткая или длинная строка опции opt_str (например, '-o' или '--option'). Если такой OptionGroup не существует, возвращается None.

Печать строки версии

Подобно строке краткого использования, optparse может также вывести строку версии вашей программы. Вы должны предоставить эту строку в качестве аргумента version в OptionParser:

parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")

%prog расширяется так же, как и в usage. Кроме этого, version может содержать все, что угодно. Когда вы предоставляете его, optparse автоматически добавляет опцию --version к вашему синтаксическому анализатору. Если он встречает эту опцию в командной строке, он расширяет вашу строку version (заменяя %prog), печатает ее в stdout и завершает работу.

Например, если ваш сценарий называется /usr/bin/foo:

$ /usr/bin/foo --version
foo 1.0

Следующие два метода можно использовать для печати и получения строки version:

OptionParser.print_version(file=None)

Выведите сообщение о версии текущей программы (self.version) в file (по умолчанию stdout). Как и в случае с print_usage(), любое вхождение %prog в self.version заменяется именем текущей программы. Ничего не делает, если self.version пуст или не определен.

OptionParser.get_version()

То же, что и print_version(), но вместо печати возвращает строку версии.

Как optparse обрабатывает ошибки

Существует два широких класса ошибок, о которых приходится беспокоиться optparse: ошибки программистов и ошибки пользователей. Ошибки программиста - это, как правило, ошибочные вызовы OptionParser.add_option(), например, недопустимые строки опций, неизвестные атрибуты опций, отсутствующие атрибуты опций и т.д. С ними борются обычным способом: вызывают исключение (либо optparse.OptionError, либо TypeError) и дают программе завершиться.

Работа с ошибками пользователя гораздо важнее, поскольку они гарантированно случаются независимо от того, насколько стабилен ваш код. optparse может автоматически обнаружить некоторые ошибки пользователя, такие как плохие аргументы опций (передача -n 4x там, где -n принимает целочисленный аргумент), пропущенные аргументы (-n в конце командной строки, где -n принимает аргумент любого типа). Кроме того, вы можете вызвать OptionParser.error() для сигнализации определенного приложением состояния ошибки:

(options, args) = parser.parse_args()
...
if options.a and options.b:
    parser.error("options -a and -b are mutually exclusive")

В любом случае, optparse обрабатывает ошибку одинаково: печатает сообщение об использовании программы и сообщение об ошибке в стандартную ошибку и завершает работу со статусом ошибки 2.

Рассмотрим первый пример, где пользователь передает 4x в опцию, которая принимает целое число:

$ /usr/bin/foo -n 4x
Usage: foo [options]

foo: error: option -n: invalid integer value: '4x'

Или, когда пользователь вообще не передает значение:

$ /usr/bin/foo -n
Usage: foo [options]

foo: error: -n option requires an argument

В генерируемых optparse- сообщениях об ошибках обязательно указывается опция, вызвавшая ошибку; не забудьте сделать то же самое при вызове OptionParser.error() из кода вашего приложения.

Если поведение обработки ошибок по умолчанию в optparse не удовлетворяет вашим потребностям, вам нужно подкласс OptionParser и переопределить его методы exit() и/или error().

Собираем все вместе

Вот как обычно выглядят сценарии, основанные на optparse::

from optparse import OptionParser
...
def main():
    usage = "usage: %prog [options] arg"
    parser = OptionParser(usage)
    parser.add_option("-f", "--file", dest="filename",
                      help="read data from FILENAME")
    parser.add_option("-v", "--verbose",
                      action="store_true", dest="verbose")
    parser.add_option("-q", "--quiet",
                      action="store_false", dest="verbose")
    ...
    (options, args) = parser.parse_args()
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if options.verbose:
        print("reading %s..." % options.filename)
    ...

if __name__ == "__main__":
    main()

Справочное руководство

Создание синтаксического анализатора

Первым шагом в использовании optparse является создание экземпляра OptionParser.

class optparse.OptionParser(...)

Конструктор OptionParser не имеет обязательных аргументов, но имеет ряд необязательных аргументов в виде ключевых слов. Вы всегда должны передавать их как аргументы ключевых слов, т.е. не полагаться на порядок объявления аргументов.

usage (по умолчанию: "%prog [options]")

Краткое описание использования, которое следует печатать, когда ваша программа выполняется неправильно или с опцией помощи. Когда optparse печатает строку использования, он расширяет %prog до os.path.basename(sys.argv[0]) (или до prog, если вы передали этот аргумент ключевого слова). Чтобы подавить сообщение об использовании, передайте специальное значение optparse.SUPPRESS_USAGE.

option_list (по умолчанию: [])

Список объектов Option для заполнения парсера. Опции в option_list добавляются после любых опций в standard_option_list (атрибут класса, который может быть установлен подклассами OptionParser), но перед любыми опциями версии или справки. Устарело; вместо этого используйте add_option() после создания парсера.

option_class (по умолчанию: optparse.Option)

Класс для использования при добавлении опций к синтаксическому анализатору в add_option().

version (по умолчанию: None)

Строка версии для печати, когда пользователь предоставляет опцию версии. Если для version задано значение true, optparse автоматически добавляет опцию версии с единственной строкой опции --version. Подстрока %prog расширяется так же, как и для usage.

conflict_handler (по умолчанию: "error")

Определяет, что делать, когда в синтаксический анализатор добавляются опции с конфликтующими строками опций; см. раздел Противоречия между вариантами.

description (по умолчанию: None)

Абзац текста, дающий краткий обзор вашей программы. optparse переформатирует этот абзац под текущую ширину терминала и печатает его, когда пользователь запрашивает помощь (после usage, но перед списком опций).

formatter (по умолчанию: новый IndentedHelpFormatter)

Экземпляр optparse.HelpFormatter, который будет использоваться для печати текста справки. optparse предоставляет два конкретных класса для этой цели: IndentedHelpFormatter и TitledHelpFormatter.

add_help_option (по умолчанию: True)

Если true, optparse добавит опцию помощи (со строками опций -h и --help) к парсеру.

prog

Строка, которую следует использовать при расширении %prog в usage и version вместо os.path.basename(sys.argv[0]).

epilog (по умолчанию: None)

Параграф текста справки, который будет напечатан после справки по опциям.

Наполнение синтаксического анализатора

Существует несколько способов заполнения синтаксического анализатора опциями. Предпочтительным является использование OptionParser.add_option(), как показано в разделе Учебник. add_option() может быть вызван одним из двух способов:

  • передать ему экземпляр Option (как возвращено командой make_option())

  • передайте ему любую комбинацию позиционных и ключевых аргументов, которые приемлемы для make_option() (т.е. для конструктора Option), и он создаст для вас экземпляр Option

Другая альтернатива - передать конструктору OptionParser список предварительно сконструированных экземпляров Option, как в:

option_list = [
    make_option("-f", "--filename",
                action="store", type="string", dest="filename"),
    make_option("-q", "--quiet",
                action="store_false", dest="verbose"),
    ]
parser = OptionParser(option_list=option_list)

(make_option() - это фабричная функция для создания экземпляров Option; в настоящее время это псевдоним конструктора Option. Будущая версия optparse может разделить Option на несколько классов, и make_option() будет выбирать нужный класс для инстанцирования. Не инстанцируйте Option напрямую).

Определение опций

Каждый экземпляр Option представляет собой набор синонимичных строк опций командной строки, например, -f и --file. Вы можете указать любое количество коротких или длинных строк опций, но вы должны указать хотя бы одну общую строку опций.

Каноническим способом создания экземпляра Option является метод add_option() в OptionParser.

OptionParser.add_option(option)
OptionParser.add_option(*opt_str, attr=value, ...)

Чтобы определить опцию с помощью только короткой строки опции:

parser.add_option("-f", attr=value, ...)

А для определения опции достаточно длинной строки опции:

parser.add_option("--foo", attr=value, ...)

Аргументы ключевых слов определяют атрибуты нового объекта Option. Наиболее важным атрибутом опции является action, и он в значительной степени определяет, какие другие атрибуты являются релевантными или необходимыми. Если вы передадите неактуальные атрибуты опции или не передадите необходимые, optparse вызовет исключение OptionError, объясняющее вашу ошибку.

Действие* опции определяет, что делает optparse, когда встречает эту опцию в командной строке. Стандартные действия опции, жестко закодированные в optparse, следующие:

"store"

хранить аргумент этой опции (по умолчанию)

"store_const"

хранить постоянное значение

"store_true"

хранить True

"store_false"

хранить False

"append"

добавить аргумент этой опции в список

"append_const"

добавление постоянного значения в список

"count"

увеличить счетчик на единицу

"callback"

вызов указанной функции

"help"

вывести сообщение об использовании, включая все опции и документацию по ним

(Если вы не указали действие, по умолчанию используется "store". Для этого действия вы также можете указать атрибуты опций type и dest; см. раздел Стандартные действия опций).

Как видите, большинство действий связано с сохранением или обновлением какого-либо значения. optparse всегда создает для этого специальный объект, условно называемый options (он бывает экземпляром optparse.Values). Аргументы опций (и различные другие значения) хранятся как атрибуты этого объекта, в соответствии с атрибутом опции dest (назначения).

Например, когда вы вызываете

parser.parse_args()

одним из первых действий optparse является создание объекта options:

options = Values()

Если одна из опций в этом синтаксическом анализаторе определена через

parser.add_option("-f", "--file", action="store", type="string", dest="filename")

и разбираемая командная строка включает любое из следующих:

-ffoo
-f foo
--file=foo
--file foo

то optparse, увидев эту опцию, сделает эквивалент

options.filename = "foo"

Атрибуты опций type и dest почти так же важны, как action, но action - единственный, который имеет смысл для всех опций.

Атрибуты опций

Следующие атрибуты опции могут быть переданы в качестве аргументов ключевого слова в OptionParser.add_option(). Если вы передаете атрибут опции, который не относится к конкретной опции, или не передаете требуемый атрибут опции, optparse выдает сообщение OptionError.

Option.action

(по умолчанию: "store")

Определяет поведение optparse, когда эта опция встречается в командной строке; доступные опции документированы here.

Option.type

(по умолчанию: "string")

Тип аргумента, ожидаемый этой опцией (например, "string" или "int"); доступные типы опций документированы here.

Option.dest

(по умолчанию: извлекается из строк опций)

Если действие опции подразумевает запись или изменение значения где-либо, это указывает optparse, куда его записать: dest называет атрибут объекта options, который optparse строит при разборе командной строки.

Option.default

Значение, используемое для назначения этой опции, если опция не видна в командной строке. См. также OptionParser.set_defaults().

Option.nargs

(по умолчанию: 1)

Сколько аргументов типа type должно быть израсходовано при появлении этой опции. Если > 1, optparse будет сохранять кортеж значений в dest.

Option.const

Для действий, которые хранят постоянное значение, постоянное значение для хранения.

Option.choices

Для опций типа "choice" - список строк, из которых пользователь может выбирать.

Option.callback

Для опций с действием "callback" - вызываемая переменная, которую следует вызывать при появлении этой опции. Подробную информацию об аргументах, передаваемых вызываемой программе, смотрите в разделе Обратные вызовы опций.

Option.callback_args
Option.callback_kwargs

Дополнительные позиционные и ключевые аргументы для передачи в callback после четырех стандартных аргументов обратного вызова.

Option.help

Текст справки, печатаемый для этой опции при выводе списка всех доступных опций после того, как пользователь ввел опцию help (например, --help). Если текст справки не предоставлен, опция будет выведена без текста справки. Чтобы скрыть эту опцию, используйте специальное значение optparse.SUPPRESS_HELP.

Option.metavar

(по умолчанию: извлекается из строк опций)

Подставка для аргумента(ов) опции, используемой при печати текста справки. Пример см. в разделе Учебник.

Стандартные действия опций

Различные действия с опциями имеют несколько разные требования и эффекты. Большинство действий имеют несколько соответствующих атрибутов опции, которые вы можете указать, чтобы направить поведение optparse; некоторые имеют обязательные атрибуты, которые вы должны указать для любой опции, использующей это действие.

  • "store" [актуально: type, dest, nargs, choices].

    За опцией должен следовать аргумент, который преобразуется в значение в соответствии с type и сохраняется в dest. Если nargs > 1, из командной строки будет потребляться несколько аргументов; все они будут преобразованы в соответствии с type и сохранены в dest в виде кортежа. См. раздел Стандартные типы опций.

    Если указано choices (список или кортеж строк), то тип по умолчанию будет "choice".

    Если type не указано, то по умолчанию используется "string".

    Если dest не задано, optparse определяет место назначения из первой длинной строки опций (например, --foo-bar подразумевает foo_bar). Если длинных строк опций нет, optparse определяет место назначения из первой короткой строки опций (например, -f подразумевает f).

    Пример:

    parser.add_option("-f")
    parser.add_option("-p", type="float", nargs=3, dest="point")
    

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

    -f foo.txt -p 1 -3.5 4 -fbar.txt
    

    optparse установит

    options.f = "foo.txt"
    options.point = (1.0, -3.5, 4.0)
    options.f = "bar.txt"
    
  • "store_const" [required: const; relevant: dest]

    Значение const сохраняется в dest.

    Пример:

    parser.add_option("-q", "--quiet",
                      action="store_const", const=0, dest="verbose")
    parser.add_option("-v", "--verbose",
                      action="store_const", const=1, dest="verbose")
    parser.add_option("--noisy",
                      action="store_const", const=2, dest="verbose")
    

    Если видно --noisy, то optparse установит

    options.verbose = 2
    
  • "store_true" [релевантно: dest]

    Частный случай "store_const", который сохраняет True до dest.

  • "store_false" [релевантно: dest]

    Как "store_true", но хранит False.

    Пример:

    parser.add_option("--clobber", action="store_true", dest="clobber")
    parser.add_option("--no-clobber", action="store_false", dest="clobber")
    
  • "append" [актуально: type, dest, nargs, choices].

    За опцией должен следовать аргумент, который добавляется к списку в dest. Если значение по умолчанию для dest не задано, пустой список создается автоматически, когда optparse впервые встречает эту опцию в командной строке. Если nargs > 1, используется несколько аргументов, и кортеж длины nargs добавляется к dest.

    Значения по умолчанию для type и dest такие же, как и для действия "store".

    Пример:

    parser.add_option("-t", "--tracks", action="append", type="int")
    

    Если в командной строке встречается -t3, то optparse делает эквивалент:

    options.tracks = []
    options.tracks.append(int("3"))
    

    Если чуть позже появится --tracks=4, это означает:

    options.tracks.append(int("4"))
    

    Действие append вызывает метод append на текущем значении опции. Это означает, что любое указанное значение по умолчанию должно иметь метод append. Это также означает, что если значение по умолчанию непустое, то элементы по умолчанию будут присутствовать в разобранном значении опции, а любые значения из командной строки будут добавлены после этих значений по умолчанию:

    >>> parser.add_option("--files", action="append", default=['~/.mypkg/defaults'])
    >>> opts, args = parser.parse_args(['--files', 'overrides.mypkg'])
    >>> opts.files
    ['~/.mypkg/defaults', 'overrides.mypkg']
    
  • "append_const" [required: const; relevant: dest]

    Как "store_const", но значение const добавляется к dest; как и в случае "append", dest по умолчанию равно None, а пустой список автоматически создается при первой встрече с опцией.

  • "count" [релевантно: dest]

    Инкрементировать целое число, хранящееся по адресу dest. Если значение по умолчанию не указано, dest устанавливается в ноль перед первым инкрементом.

    Пример:

    parser.add_option("-v", action="count", dest="verbosity")
    

    В первый раз, когда -v встречается в командной строке, optparse делает эквивалент:

    options.verbosity = 0
    options.verbosity += 1
    

    Каждое последующее появление -v приводит к

    options.verbosity += 1
    
  • "callback" [требуется: callback; актуально: type, nargs, callback_args, callback_kwargs].

    Вызовите функцию, указанную callback, которая вызывается как

    func(option, opt_str, value, parser, *args, **kwargs)
    

    Более подробно см. раздел Обратные вызовы опций.

  • "help"

    Вызовите функцию, указанную usage, которая вызывается как

    Если для опции не задана строка help, она все равно будет указана в справочном сообщении. Чтобы полностью исключить опцию, используйте специальное значение optparse.SUPPRESS_HELP.

    optparse автоматически добавляет опцию help ко всем OptionParsers, поэтому обычно вам не нужно ее создавать.

    Пример:

    from optparse import OptionParser, SUPPRESS_HELP
    
    # usually, a help option is added automatically, but that can
    # be suppressed using the add_help_option argument
    parser = OptionParser(add_help_option=False)
    
    parser.add_option("-h", "--help", action="help")
    parser.add_option("-v", action="store_true", dest="verbose",
                      help="Be moderately verbose")
    parser.add_option("--file", dest="filename",
                      help="Input file to read data from")
    parser.add_option("--secret", help=SUPPRESS_HELP)
    

    Если optparse видит в командной строке -h или --help, он выводит в stdout что-то вроде следующего справочного сообщения (предполагая, что sys.argv[0] - это "foo.py"):

    Usage: foo.py [options]
    
    Options:
      -h, --help        Show this help message and exit
      -v                Be moderately verbose
      --file=FILENAME   Input file to read data from
    

    После печати справочного сообщения optparse завершает ваш процесс командой sys.exit(0).

  • "version"

    Выводит номер версии, переданный OptionParser, на stdout и завершает работу. Номер версии фактически форматируется и выводится методом print_version() OptionParser. Обычно имеет значение, только если аргумент version передан в конструктор OptionParser. Как и в случае с опциями help, вы редко будете создавать опции version, поскольку optparse автоматически добавляет их, когда это необходимо.

Стандартные типы опций

optparse имеет пять встроенных типов опций: "string", "int", "choice", "float" и "complex". Если вам необходимо добавить новые типы опций, см. раздел Расширение optparse.

Аргументы строковых опций никак не проверяются и не преобразуются: текст командной строки сохраняется в месте назначения (или передается в обратный вызов) как есть.

Целочисленные аргументы (тип "int") разбираются следующим образом:

  • если число начинается с 0x, оно разбирается как шестнадцатеричное число

  • если число начинается с 0, оно разбирается как восьмеричное число

  • если число начинается с 0b, оно разбирается как двоичное число

  • в противном случае, число анализируется как десятичное число

Преобразование выполняется вызовом int() с соответствующим основанием (2, 8, 10 или 16). Если это не удается, то и optparse тоже, хотя с более полезным сообщением об ошибке.

Аргументы опций "float" и "complex" преобразуются непосредственно с помощью float() и complex(), с аналогичной обработкой ошибок.

Опции "choice" являются подтипом опций "string". Атрибут опции choices (последовательность строк) определяет набор допустимых аргументов опции. optparse.check_choice() сравнивает аргументы опций, предоставленные пользователем, с этим основным списком и выдает сообщение OptionValueError, если указана недопустимая строка.

Разбор аргументов

Весь смысл создания и наполнения OptionParser заключается в вызове его метода parse_args():

(options, args) = parser.parse_args(args=None, values=None)

где входными параметрами являются

args

список аргументов для обработки (по умолчанию: sys.argv[1:])

values

объект optparse.Values для хранения аргументов опции (по умолчанию: новый экземпляр Values) – если вы передадите существующий объект, параметры опции по умолчанию не будут инициализированы на нем

а возвращаемыми значениями являются

options

тот же объект, который был передан как values, или экземпляр optparse.Values, созданный optparse.

args

оставшиеся позиционные аргументы после обработки всех опций

Наиболее распространенным вариантом использования является предоставление ни одного из аргументов ключевого слова. Если вы передадите values, оно будет модифицировано многократными вызовами setattr() (примерно по одному на каждый аргумент опции, сохраненный в пункте назначения опции) и возвращено parse_args().

Если parse_args() встречает какие-либо ошибки в списке аргументов, он вызывает метод OptionParser error() с соответствующим сообщением об ошибке для конечного пользователя. В итоге ваш процесс завершается со статусом выхода 2 (традиционный статус выхода Unix для ошибок командной строки).

Запросы и манипуляции с анализатором опций

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

OptionParser.disable_interspersed_args()

Устанавливает остановку синтаксического разбора на первом неопционе. Например, если -a и -b - простые опции, не принимающие аргументов, то optparse обычно принимает такой синтаксис:

prog -a arg1 -b arg2

и рассматривает его как эквивалент

prog -a -b arg1 arg2

Чтобы отключить эту функцию, вызовите disable_interspersed_args(). Это восстанавливает традиционный синтаксис Unix, где разбор опций останавливается на первом аргументе, не являющемся опцией.

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

OptionParser.enable_interspersed_args()

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

OptionParser.get_option(opt_str)

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

OptionParser.has_option(opt_str)

Возвращает True, если OptionParser имеет опцию со строкой опции opt_str (например, -q или --verbose).

OptionParser.remove_option(opt_str)

Если OptionParser имеет опцию, соответствующую opt_str, эта опция удаляется. Если эта опция содержала какие-либо другие строки опций, все эти строки опций становятся недействительными. Если opt_str не встречается ни в одной опции, принадлежащей данному OptionParser, возникает ошибка ValueError.

Противоречия между вариантами

Если вы не будете осторожны, легко определить опции с противоречивыми строками опций:

parser.add_option("-n", "--dry-run", ...)
...
parser.add_option("-n", "--noisy", ...)

(Это особенно верно, если вы определили свой собственный подкласс OptionParser с некоторыми стандартными опциями).

Каждый раз, когда вы добавляете опцию, optparse проверяет ее на наличие конфликтов с существующими опциями. Если таковые обнаруживаются, то вызывается текущий механизм обработки конфликтов. Вы можете задать механизм обработки конфликтов либо в конструкторе:

parser = OptionParser(..., conflict_handler=handler)

или с помощью отдельного вызова:

parser.set_conflict_handler(handler)

Доступными обработчиками конфликтов являются:

"error" (по умолчанию)

предположить, что конфликты опций являются ошибкой программирования и поднять OptionConflictError

"resolve"

грамотно разрешать конфликты опционов (см. ниже)

В качестве примера, давайте определим OptionParser, который разумно разрешает конфликты, и добавим к нему конфликтующие опции:

parser = OptionParser(conflict_handler="resolve")
parser.add_option("-n", "--dry-run", ..., help="do no harm")
parser.add_option("-n", "--noisy", ..., help="be noisy")

В этот момент optparse обнаруживает, что ранее добавленная опция уже использует строку опции -n. Поскольку conflict_handler является "resolve", он разрешает ситуацию, удаляя -n из списка строк опций предыдущей опции. Теперь --dry-run является единственным способом для пользователя активировать эту опцию. Если пользователь попросит помощи, в сообщении справки это будет отражено:

Options:
  --dry-run     do no harm
  ...
  -n, --noisy   be noisy

Можно уничтожить строки опций для ранее добавленной опции, пока их не останется, и у пользователя не будет возможности вызвать эту опцию из командной строки. В этом случае optparse полностью удаляет эту опцию, так что она не будет отображаться в тексте справки или где-либо еще. Продолжая работу с нашим существующим OptionParser:

parser.add_option("--dry-run", ..., help="new dry-run option")

В этот момент исходная опция -n/--dry-run уже недоступна, поэтому optparse удаляет ее, оставляя следующий текст справки:

Options:
  ...
  -n, --noisy   be noisy
  --dry-run     new dry-run option

Очистка

Экземпляры OptionParser имеют несколько циклических ссылок. Это не должно быть проблемой для сборщика мусора Python, но вы можете захотеть явно разорвать циклические ссылки, вызвав destroy() на вашем OptionParser, когда вы закончите работу с ним. Это особенно полезно в длительно работающих приложениях, где большие графы объектов доступны из вашего OptionParser.

Другие методы

OptionParser поддерживает несколько других публичных методов:

OptionParser.set_usage(usage)

Установите строку использования в соответствии с правилами, описанными выше для аргумента ключевого слова конструктора usage. Передача None устанавливает строку использования по умолчанию; используйте optparse.SUPPRESS_USAGE для подавления сообщения об использовании.

OptionParser.print_usage(file=None)

Выведите сообщение об использовании текущей программы (self.usage) в file (по умолчанию stdout). Любое вхождение строки %prog в self.usage заменяется именем текущей программы. Ничего не делает, если self.usage пуст или не определен.

OptionParser.get_usage()

То же, что и print_usage(), но вместо печати возвращает строку использования.

OptionParser.set_defaults(dest=value, ...)

Установите значения по умолчанию сразу для нескольких пунктов назначения опций. Использование set_defaults() является предпочтительным способом установки значений по умолчанию для опций, так как несколько опций могут использовать один и тот же пункт назначения. Например, если несколько опций «mode» задают одно и то же место назначения, любая из них может установить значение по умолчанию, и победит последняя:

parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced",
                  default="novice")    # overridden below
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice",
                  default="advanced")  # overrides above setting

Чтобы избежать этой путаницы, используйте set_defaults():

parser.set_defaults(mode="advanced")
parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced")
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice")

Обратные вызовы опций

Когда встроенных действий и типов optparse недостаточно для ваших нужд, у вас есть два варианта: расширить optparse или определить опцию обратного вызова. Расширение optparse является более общим, но избыточным для многих простых случаев. Довольно часто простой обратный вызов - это все, что вам нужно.

Определение опции обратного вызова состоит из двух этапов:

  • определить саму опцию с помощью действия "callback"

  • написать обратный вызов; это функция (или метод), которая принимает не менее четырех аргументов, как описано ниже

Определение опции обратного вызова

Как всегда, самый простой способ определить опцию обратного вызова - это использовать метод OptionParser.add_option(). Кроме action, единственным атрибутом опции, который вы должны указать, является callback, функция для вызова:

parser.add_option("-c", action="callback", callback=my_callback)

callback - это функция (или другой вызываемый объект), поэтому вы должны были уже определить my_callback() при создании этой опции обратного вызова. В этом простом случае optparse даже не знает, принимает ли -c какие-либо аргументы, что обычно означает, что опция не принимает никаких аргументов - простое присутствие -c в командной строке - это все, что ей нужно знать. Однако в некоторых обстоятельствах вы можете захотеть, чтобы ваш обратный вызов потреблял произвольное количество аргументов командной строки. Именно в этом случае написание обратных вызовов становится сложной задачей; об этом мы поговорим позже в этом разделе.

optparse всегда передает четыре определенных аргумента вашему обратному вызову, а дополнительные аргументы будут передаваться только в том случае, если вы укажете их через callback_args и callback_kwargs. Таким образом, минимальная сигнатура функции обратного вызова выглядит так:

def my_callback(option, opt, value, parser):

Четыре аргумента обратного вызова описаны ниже.

Существует несколько других атрибутов опции, которые вы можете указать при определении опции обратного вызова:

type

имеет свое обычное значение: как и в случае с действиями "store" или "append", он инструктирует optparse потреблять один аргумент и преобразовывать его в type. Однако вместо того, чтобы хранить преобразованное значение (значения) где-либо, optparse передает его вашей функции обратного вызова.

nargs

также имеет свое обычное значение: если оно задано и > 1, optparse будет потреблять nargs аргументов, каждый из которых должен быть преобразован в type. Затем он передает кортеж преобразованных значений в ваш обратный вызов.

callback_args

кортеж дополнительных позиционных аргументов для передачи обратному вызову

callback_kwargs

словарь дополнительных аргументов ключевых слов для передачи обратному вызову

Как вызываются обратные вызовы

Все обратные вызовы вызываются следующим образом:

func(option, opt_str, value, parser, *args, **kwargs)

где

option

это экземпляр Option, который вызывает обратный вызов

opt_str

это строка опции в командной строке, которая вызывает обратный вызов. (Если была использована сокращенная длинная опция, opt_str будет полной, канонической строкой опции - например, если пользователь ввел --foo в командной строке как сокращение для --foobar, то opt_str будет "--foobar").

value

это строка опции в командной строке, которая вызывает обратный вызов. (Если была использована сокращенная длинная опция, optparse будет полной, канонической строкой опции - например, если пользователь ввел type в командной строке как сокращение для value, то type будет None).

parser

это экземпляр OptionParser, управляющий всем процессом, в основном полезный потому, что вы можете получить доступ к некоторым другим интересным данным через атрибуты его экземпляра:

parser.largs

текущий список оставшихся аргументов, то есть аргументов, которые были потреблены, но не являются ни опциями, ни аргументами опций. Не стесняйтесь изменять parser.largs, например, добавляя в него дополнительные аргументы. (Этот список станет args, вторым возвращаемым значением parse_args()).

parser.rargs

текущий список оставшихся аргументов, т.е. с удаленными opt_str и value (если применимо) и только следующими за ними аргументами. Не стесняйтесь модифицировать parser.rargs, например, потребляя больше аргументов.

parser.values

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

args

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

kwargs

это словарь произвольных аргументов ключевых слов, передаваемых через callback_kwargs.

Возбуждение ошибок в обратном вызове

Функция обратного вызова должна поднять OptionValueError, если возникли проблемы с опцией или ее аргументом(ами). optparse поймает это и завершит программу, напечатав сообщение об ошибке, которое вы предоставите на stderr. Ваше сообщение должно быть ясным, кратким, точным и содержать упоминание о неисправной опции. В противном случае пользователю будет трудно понять, что он сделал не так.

Пример обратного вызова 1: тривиальный обратный вызов

Вот пример опции обратного вызова, которая не принимает аргументов и просто записывает, что опция была замечена:

def record_foo_seen(option, opt_str, value, parser):
    parser.values.saw_foo = True

parser.add_option("--foo", action="callback", callback=record_foo_seen)

Конечно, это можно сделать с помощью действия "store_true".

Пример обратного вызова 2: проверка опционного заказа

Вот чуть более интересный пример: зафиксируйте факт появления -a, но взорвитесь, если он появится после -b в командной строке.

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use -a after -b")
    parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")

Пример обратного вызова 3: проверка опционного заказа (обобщенный)

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

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use %s after -b" % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')

Пример обратного вызова 4: проверка произвольного условия

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

def check_moon(option, opt_str, value, parser):
    if is_moon_full():
        raise OptionValueError("%s option invalid when moon is full"
                               % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
                  action="callback", callback=check_moon, dest="foo")

(Определение is_moon_full() остается в качестве упражнения для читателя).

Пример обратного вызова 5: фиксированные аргументы

Ситуация становится немного интереснее, когда вы определяете опции обратного вызова, которые принимают фиксированное количество аргументов. Указание того, что опция обратного вызова принимает аргументы, аналогично определению опции "store" или "append": если вы определяете type, то опция принимает один аргумент, который должен быть приведен к этому типу; если вы далее определяете nargs, то опция принимает nargs аргументов.

Вот пример, который просто эмулирует стандартное действие "store":

def store_value(option, opt_str, value, parser):
    setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
                  action="callback", callback=store_value,
                  type="int", nargs=3, dest="foo")

Обратите внимание, что optparse позаботится о получении 3 аргументов и преобразовании их в целые числа за вас; все, что вам нужно сделать, это сохранить их. (Или что угодно; очевидно, что для этого примера вам не нужен обратный вызов).

Пример обратного вызова 6: аргументы переменных

Ситуация осложняется, когда вы хотите, чтобы опция принимала переменное количество аргументов. Для этого случая вы должны написать обратный вызов, поскольку optparse не предоставляет для этого никаких встроенных возможностей. И вам придется иметь дело с некоторыми тонкостями обычного разбора командной строки Unix, которые optparse обычно обрабатывает за вас. В частности, обратные вызовы должны реализовать обычные правила для голых аргументов -- и -:

  • Ситуация осложняется, когда вы хотите, чтобы опция принимала переменное количество аргументов. Для этого случая вы должны написать обратный вызов, поскольку -- не предоставляет для этого никаких встроенных возможностей. И вам придется иметь дело с некоторыми тонкостями обычного разбора командной строки Unix, которые - обычно обрабатывает за вас. В частности, обратные вызовы должны реализовать обычные правила для голых аргументов и :

  • bare -- (если не является аргументом какой-либо опции): остановить обработку командной строки и отбросить --.

  • bare - (если не является аргументом какой-либо опции): остановить обработку командной строки, но сохранить - (добавить его к parser.largs)

Если вам нужна опция, принимающая переменное количество аргументов, то здесь есть несколько тонких и сложных моментов, о которых нужно побеспокоиться. Точная реализация, которую вы выберете, будет основана на том, на какие компромиссы вы готовы пойти для своего приложения (вот почему optparse не поддерживает такие вещи напрямую).

Тем не менее, вот попытка сделать обратный вызов для опции с переменными аргументами:

def vararg_callback(option, opt_str, value, parser):
    assert value is None
    value = []

    def floatable(str):
        try:
            float(str)
            return True
        except ValueError:
            return False

    for arg in parser.rargs:
        # stop on --foo like options
        if arg[:2] == "--" and len(arg) > 2:
            break
        # stop on -a, but not on -3 or -3.0
        if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
            break
        value.append(arg)

    del parser.rargs[:len(value)]
    setattr(parser.values, option.dest, value)

...
parser.add_option("-c", "--callback", dest="vararg_attr",
                  action="callback", callback=vararg_callback)

Расширение optparse

Поскольку двумя основными факторами, определяющими то, как optparse интерпретирует опции командной строки, являются действие и тип каждой опции, наиболее вероятным направлением расширения является добавление новых действий и новых типов.

Добавление новых типов

Чтобы добавить новые типы, необходимо определить свой собственный подкласс класса optparse Option. Этот класс имеет несколько атрибутов, определяющих типы optparse: TYPES и TYPE_CHECKER.

Option.TYPES

Кортеж имен типов; в своем подклассе просто определите новый кортеж TYPES, который основывается на стандартном.

Option.TYPE_CHECKER

Словарь, отображающий имена типов на функции проверки типов. Функция проверки типов имеет следующую сигнатуру:

def check_mytype(option, opt, value)

Чтобы добавить новые типы, необходимо определить свой собственный подкласс класса option Option. Этот класс имеет несколько атрибутов, которые определяют типы opt: -f и value.

Ваша функция проверки типов должна выдать сообщение OptionValueError, если она столкнется с какими-либо проблемами. OptionValueError принимает единственный строковый аргумент, который передается как есть методу OptionParser error(), который, в свою очередь, добавляет имя программы и строку "error:" и печатает все в stderr перед завершением процесса.

Вот глупый пример, демонстрирующий добавление типа опции "complex" для анализа комплексных чисел в стиле Python в командной строке. (Это еще глупее, чем было раньше, потому что в версии optparse 1.3 добавлена встроенная поддержка комплексных чисел, но не важно).

Во-первых, необходимый импорт:

from copy import copy
from optparse import Option, OptionValueError

Сначала вам нужно определить ваш средство проверки типов, поскольку на него будут ссылаться позже (в атрибуте класса TYPE_CHECKER вашего подкласса Option):

def check_complex(option, opt, value):
    try:
        return complex(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid complex value: %r" % (opt, value))

Наконец, подкласс Option:

class MyOption (Option):
    TYPES = Option.TYPES + ("complex",)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["complex"] = check_complex

(Если бы мы не сделали copy() из Option.TYPE_CHECKER, мы бы в итоге изменили атрибут TYPE_CHECKER класса Option класса optparse. Это Python, и ничто не мешает вам сделать это, кроме хороших манер и здравого смысла).

Вот и все! Теперь вы можете написать сценарий, использующий новый тип опции, как и любой другой сценарий на основе optparse, за исключением того, что вы должны указать OptionParser использовать MyOption вместо Option:

parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")

В качестве альтернативы вы можете составить свой собственный список опций и передать его OptionParser; если вы не используете add_option() в вышеописанном способе, вам не нужно указывать OptionParser, какой класс опций использовать:

option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)

Добавление новых действий

Добавление новых действий немного сложнее, потому что вы должны понимать, что optparse имеет несколько классификаций для действий:

действия «магазина»

действия, в результате которых optparse сохраняется значение для атрибута текущего экземпляра OptionValues; эти опции требуют, чтобы атрибут dest был предоставлен конструктору Option.

«набранные» действия

действия, которые принимают значение из командной строки и ожидают, что оно будет определенного типа; точнее, строка, которая может быть преобразована к определенному типу. Эти опции требуют атрибута type в конструкторе Option.

действия, которые принимают значение из командной строки и ожидают, что оно будет определенного типа; точнее, строка, которая может быть преобразована к определенному типу. Эти опции требуют атрибута "store" в конструкторе Option.

Когда вы добавляете действие, вам необходимо классифицировать его, включив его хотя бы в один из следующих атрибутов класса Option (все они являются списками строк):

Option.ACTIONS

Все действия должны быть перечислены в разделе ACTIONS.

Option.STORE_ACTIONS

Действия «хранить» дополнительно перечислены здесь.

Option.TYPED_ACTIONS

«Набранные» действия дополнительно перечислены здесь.

Option.ALWAYS_TYPED_ACTIONS

Действия, которые всегда принимают тип (т.е. чьи опции всегда принимают значение), дополнительно перечислены здесь. Единственный эффект этого заключается в том, что optparse присваивает тип по умолчанию, "string", опциям без явного типа, действие которых перечислено в ALWAYS_TYPED_ACTIONS.

Для того чтобы действительно реализовать ваше новое действие, вы должны переопределить метод Option take_action() и добавить case, который распознает ваше действие.

Например, добавим действие "extend". Оно похоже на стандартное действие "append", но вместо того, чтобы принимать одно значение из командной строки и добавлять его к существующему списку, "extend" будет принимать несколько значений в одной строке, разделенной запятыми, и расширять ими существующий список. То есть, если --names является опцией "extend" типа "string", то командная строка

--names=foo,bar --names blah --names ding,dong

приведет к списку

["foo", "bar", "blah", "ding", "dong"]

И снова мы определяем подкласс Option:

class MyOption(Option):

    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            lvalue = value.split(",")
            values.ensure_value(dest, []).extend(lvalue)
        else:
            Option.take_action(
                self, action, dest, opt, value, values, parser)

Особенности:

  • "extend" как ожидает значение в командной строке, так и сохраняет его где-то, поэтому оно входит и в STORE_ACTIONS, и в TYPED_ACTIONS.

  • чтобы убедиться, что optparse присваивает действиям "string" тип по умолчанию "extend", мы помещаем действие "extend" также в ALWAYS_TYPED_ACTIONS.

  • MyOption.take_action() реализует только это новое действие, и передает управление обратно Option.take_action() для стандартных действий optparse.

  • values является экземпляром класса optparse_parser.Values, который предоставляет очень полезный метод ensure_value(). ensure_value() по сути является getattr() с предохранительным клапаном; он вызывается как

    values.ensure_value(attr, value)
    

    Если атрибут attr в values не существует или равен None, то функция ensure_value() сначала устанавливает его в value, а затем возвращает „значение“. Это очень удобно для таких действий, как "extend", "append" и "count", которые накапливают данные в переменной и ожидают, что эта переменная будет определенного типа (список для первых двух, целое число для последнего). Использование ensure_value() означает, что сценариям, использующим ваше действие, не нужно беспокоиться об установке значения по умолчанию для рассматриваемых опциональных направлений; они могут просто оставить значение по умолчанию None, а ensure_value() позаботится о том, чтобы все было правильно, когда это потребуется.

Вернуться на верх