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

Источник: Lib/optparse.py

Не рекомендуется, начиная с версии 3.2: Модуль optparse является soft deprecated и не будет развиваться дальше; разработка будет продолжена для модуля 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 различных частей информации, не имеет особого значения, каким образом вы получите эту информацию от пользователя - большинство людей сдадутся и уйдут, прежде чем успешно запустят программу. Это касается и командной строки, и файла конфигурации, и графического интерфейса: если вы предъявляете к пользователям столько требований, большинство из них просто сдадутся.

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

Учебное пособие

Хотя 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"

хранить постоянное значение, предварительно установленное через Option.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]

(Если вывод справки вызван опцией справки, 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) в файл (по умолчанию 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)

Параграф текста справки, который нужно напечатать после опции help.

Наполнение парсера

Существует несколько способов заполнения парсера опциями. Предпочтительным является использование 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"

хранить постоянное значение, предварительно установленное через Option.const.

"store_true"

магазин True

"store_false"

магазин False

"append"

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

"append_const"

добавить константное значение в список, предварительно заданное через Option.const.

"count"

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

"callback"

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

"help"

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

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

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

class optparse.Values

Объект, содержащий разобранные имена аргументов и значения в качестве атрибутов. Обычно создается вызовом при обращении к OptionParser.parse_args(), и может быть переопределен пользовательским подклассом, переданным в аргумент values в OptionParser.parse_args() (как описано в Разбор аргументов).

Аргументы опций (и различные другие значения) хранятся как атрибуты этого объекта в соответствии с атрибутом опции 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 - единственный, который имеет смысл для всех опций.

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

class optparse.Option

Единственный аргумент командной строки, различные атрибуты которого передаются в конструктор по ключевому слову. Обычно создается с помощью OptionParser.add_option(), а не напрямую, и может быть переопределена пользовательским классом с помощью аргумента option_class в OptionParser.

Следующие атрибуты опций могут быть переданы в качестве аргументов ключевого слова в 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" [требуется: const; актуально: 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, то используется несколько аргументов, и к dest добавляется кортеж длины nargs.

    Установки по умолчанию для 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" [требуется: const; актуально: 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, переданной в конструктор OptionParser, и строки help, переданной каждой опции.

    Если для опции не задана строка 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. Обычно имеет значение только в том случае, если в конструкторе OptionParser указан аргумент version. Как и в случае с опциями 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().

OptionParser.parse_args(args=None, values=None)

Разбор параметров командной строки, содержащихся в args.

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

args

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

values

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

а возвращаемое значение - пара (options, args), где

options

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

args

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

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

Если parse_args() встречает какие-либо ошибки в списке аргументов, он вызывает метод error() OptionParser с соответствующим сообщением об ошибке для конечного пользователя. В итоге ваш процесс завершается со статусом выхода 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)

Возвращает экземпляр Option со строкой опций opt_str, или None, если ни одна опция не имеет такой строки опций.

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) в файл (по умолчанию 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 (аргумент не ожидается), то value будет None. Если nargs > 1, то value будет кортежем значений соответствующего типа.

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. В частности, обратные вызовы должны реализовывать обычные правила для голых -- и - аргументов:

  • В качестве аргументов опции могут быть либо --, либо -

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

  • Голый - (если не является аргументом какой-либо опции): прекращает обработку командной строки, но сохраняет - (добавляет его к 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 - строка из командной строки, которую необходимо проверить и преобразовать к нужному типу. check_mytype() должен вернуть объект гипотетического типа mytype. Значение, возвращенное функцией проверки типа, попадет в экземпляр OptionValues, возвращаемый OptionParser.parse_args(), или будет передано в обратный вызов в качестве параметра 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", "store_const", "append" и "count", а «печатные» действия по умолчанию - "store", "append" и "callback".

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

Option.ACTIONS

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

Option.STORE_ACTIONS

Здесь также перечислены действия, связанные с «магазином».

Option.TYPED_ACTIONS

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

Option.ALWAYS_TYPED_ACTIONS

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

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

Например, добавим действие "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 присваивает действиям "extend" тип по умолчанию "string", мы поместили действие "extend" также в ALWAYS_TYPED_ACTIONS.

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

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

    values.ensure_value(attr, value)
    

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

Исключения

exception optparse.OptionError

Возникает, если экземпляр Option создается с недопустимыми или противоречивыми аргументами.

exception optparse.OptionConflictError

Возникает, если в OptionParser добавлены конфликтующие опции.

exception optparse.OptionValueError

Возникает, если в командной строке встречается недопустимое значение опции.

exception optparse.BadOptionError

Возникает, если в командной строке передана недопустимая опция.

exception optparse.AmbiguousOptionError

Возникает, если в командной строке передана двусмысленная опция.