Документация Python неофициальный перевод
Содержание страницы

optparse – более мощный парсер опций командной строкиoptparse – More powerful command line option parser

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.verboseFalse. 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]).

ПредысторияBackground

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

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

аргумент

строка, введённая в командной строке и переданная оболочкой в 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 и никогда не будут. Это сделано намеренно: первые три нестандартны в любом окружении, а последний имеет смысл только в том случае, если программа ориентирована исключительно на VMS, MS-DOS и/или Windows.

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

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

-f foo
--file foo

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

-ffoo
--file=foo

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

позиционный аргумент
то, что остаётся в списке аргументов после разбора опций, то есть после того, как опции и их аргументы были разобраны и удалены из списка аргументов.
обязательная опция
опция, которая должна быть указана в командной строке; обратите внимание, что фраза «обязательная опция» внутренне противоречива. optparse не препятствует реализации обязательных опций, но и не особо помогает в этом. См. examples/required_1.py и examples/required_2.py в дистрибутиве исходного кода optparse для двух способов реализации обязательных опций с помощью optparse.

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

prog -v --report /tmp/report.txt foo bar

"-v" и "--report" – это опции. Если предположить, что --report принимает один аргумент, то "/tmp/report.txt" – это аргумент опции. "foo" и "bar" – это позиционные аргументы.

Для чего нужны опции?What are options for?

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

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

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

cp SOURCE DEST
cp SOURCE ... DEST-DIR

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

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

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

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

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

Учебное руководствоTutorial

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

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

Строки опций, передаваемые в 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 является основным.

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

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

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

Действие storeThe store action

Наиболее распространённое действие опции – 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. Добавление типов описано в разделе Extending optparse.

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

Опции-флаги – установка переменной в 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.

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

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

store_const
сохранить константное значение
append
добавить аргумент этой опции в список
count
увеличить счётчик на единицу
колбэк
вызвать указанную функцию

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

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

Все приведённые выше примеры подразумевают установку некоторой переменной (так называемого «назначения») при встрече определённых параметров командной строки. Что произойдёт, если эти параметры ни разу не встретятся? Поскольку мы не указали значения по умолчанию, все они будут установлены в 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()

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

Генерация справкиGenerating help

Возможность 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]). Затем расширенная строка выводится перед подробной справкой по опциям.

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

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

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

    -m MODE, --mode=MODE
    

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

    -f FILE, --filename=FILE
    

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

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

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

Продолжая работать с анализатором, определённым выше, добавить 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:  [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)
  -fFILE, --file=FILE  write output to FILE
  -mMODE, --mode=MODE  interaction mode: one of 'novice', 'intermediate'
                       [default], 'expert'

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

Печать строки версииPrinting a version string

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

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

"%prog" is expanded just like it is in usage. Apart from that, version can contain anything you like. When you supply it, optparse automatically adds a "--version" option to your parser. If it encounters this option on the command line, it expands your version string (by replacing "%prog"), prints it to stdout, and exits.

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

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

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

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

Обработка ошибок пользователя гораздо важнее, поскольку они гарантированно будут возникать независимо от стабильности кода. optparse может автоматически обнаруживать некоторые ошибки пользователя, такие как неверные аргументы опций (передача "-n 4x", где -n ожидает целочисленный аргумент), отсутствие аргументов ("-n" в конце командной строки, где -n принимает аргумент любого типа). Кроме того, можно вызвать parser.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, всегда указывают опцию, связанную с ошибкой; обязательно делайте то же самое при вызове parser.error() из кода приложения.

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

Собираем всё вместеPutting it all together

Вот как обычно выглядят сценарии на основе 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()

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

Создание парсераCreating the parser

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

parser = OptionParser(...)

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

usage (по умолчанию: "%prog [options]")
Краткое описание использования (usage), которое выводится при неверном запуске программы или при запросе справки. Когда optparse выводит строку usage, он заменяет %prog на os.path.basename(sys.argv[0]) (или на prog, если был передан этот именованный аргумент). Чтобы отключить вывод сообщения usage, передайте специальное значение optparse.SUPPRESS_USAGE.
option_list (по умолчанию: [])
Список объектов Option для заполнения анализатора. Опции из option_list добавляются после всех опций из standard_option_list (атрибут класса, который может быть установлен подклассами OptionParser), но перед любыми опциями версии или справки. Устарело; используйте add_option() после создания анализатора.
option_class (по умолчанию: optparse.Option)
Класс, используемый при добавлении опций в анализатор с помощью add_option().
version (по умолчанию: None)
Строка версии, которая выводится, когда пользователь указывает опцию версии. Если передать истинное значение для version, 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]).

Заполнение парсераPopulating the parser

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

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

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

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 напрямую.)

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

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

Канонический способ создания экземпляра Option – с помощью метода add_option() класса OptionParser:

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

Для определения опции только с короткой строкой опции:

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

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

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

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

Атрибут action опции определяет, что optparse делает при встрече этой опции в командной строке. Стандартные действия опций, жёстко закодированные в optparse:

store
сохранить аргумент опции (по умолчанию)
store_const
сохранить константное значение
store_true
сохраняет истинное значение
store_false
сохраняет ложное значение
append
добавить аргумент этой опции в список
append_const
добавить константное значение в список
count
увеличить счётчик на единицу
колбэк
вызвать указанную функцию
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 – единственный, который имеет смысл для всех опций.

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

Различные действия опций имеют несколько разные требования и эффекты. Большинство действий имеют несколько соответствующих атрибутов, которые можно указать, чтобы направить поведение 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, который сохраняет истинное значение в dest.

  • store_false [значимые: dest]

    Как и store_true, но сохраняет ложное значение.

    Пример:

    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_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
    
  • колбэк [обязательно: колбэк; связанные: type, nargs, callback_args, callback_kwargs]

    Вызывает функцию, заданную колбэк, которая вызывается как

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

    Смотрите раздел Колбэки опций для подробностей.

  • справка

    Печатает полное сообщение справки для всех опций текущего анализатора опций. Сообщение справки формируется из строки usage, переданной конструктору OptionParser, и строки справка, переданной каждой опции.

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

    optparse автоматически добавляет опцию справка во все объекты OptionParser, поэтому обычно нет необходимости создавать её вручную.

    Пример:

    from optparse import OptionParser, SUPPRESS_HELP
    
    parser = OptionParser()
    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).

  • версия

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

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

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

  • действие (по умолчанию: "store")

    Определяет поведение optparse при обнаружении этой опции в командной строке; доступные варианты описаны выше.

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

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

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

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

  • default (устарело)

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

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

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

  • константа

    Для действий, сохраняющих постоянное значение, – само это постоянное значение.

  • варианты_выбора

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

  • колбэк

    Для опций с действием "колбэк" – вызываемый объект, который вызывается при обнаружении этой опции. Подробнее об аргументах, передаваемых в callable, см. раздел Колбэки опций.

  • callback_args, callback_kwargs

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

  • справка

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

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

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

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

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, если указана недопустимая строка.

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

Весь смысл создания и настройки OptionParser – вызвать его метод parse_args():

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

где входные параметры:

args
список аргументов для обработки (по умолчанию: sys.argv[1:])
values
объект для хранения аргументов опций (по умолчанию: новый экземпляр optparse.Values)

а возвращаемые значения –

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

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

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

Запросы и изменение вашего парсера опцийQuerying and manipulating your option parser

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

disable_interspersed_args()
Устанавливает режим разбора, при котором разбор останавливается на первом не-опционном аргументе. Используйте это, если у вас есть обработчик команд, который запускает другую команду, имеющую собственные опции, и вы хотите быть уверены, что эти опции не будут перепутаны. Например, каждая команда может иметь свой набор опций.
enable_interspersed_args()
Устанавливает режим разбора, при котором разбор не останавливается на первом не-опционном аргументе, позволяя перемешивать флаги с аргументами команды. Например, "-s arg1 --long arg2" вернёт ["arg1", "arg2"] в качестве аргументов команды, а -s, --long – как опции. Это поведение по умолчанию.
get_option(opt_str)
Возвращает экземпляр Option с опционной строкой opt_str или None, если ни одна опция не имеет такой опционной строки.
has_option(opt_str)
Возвращает true, если OptionParser имеет опцию с опционной строкой opt_str (например, "-q" или "--verbose").
remove_option(opt_str)
Если OptionParser содержит опцию, соответствующую opt_str, эта опция удаляется. Если эта опция предоставляла какие-либо другие опционные строки, все эти опционные строки становятся недействительными. Если opt_str не встречается ни в одной опции, принадлежащей этому OptionParser, возбуждается ValueError.

Конфликты между опциямиConflicts between options

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

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

ОчисткаCleanup

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

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

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

  • set_usage(usage)

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

  • enable_interspersed_args(), disable_interspersed_args()

    Enable/disable positional arguments interspersed with options, similar to GNU getopt (enabled by default). For example, if "-a" and "-b" are both simple options that take no arguments, optparse normally accepts this syntax:

    prog -a arg1 -b arg2
    

    и обрабатывает его как эквивалент

    prog -a -b arg1 arg2
    

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

  • set_defaults(dest=value, ...)

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

    parser.add_option("--advanced", action="store_const",
                      dest="mode", const="advanced",
                      default="novice")    # переопределено ниже
    parser.add_option("--novice", action="store_const",
                      dest="mode", const="novice",
                      default="advanced")  # переопределяет вышеуказанную настройку
    

    Чтобы избежать этой путаницы, используйте 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")
    

Колбэки опцийOption Callbacks

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

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

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

Определение опции-колбэкаDefining a callback option

As always, the easiest way to define a callback option is by using the parser.add_option() method. Apart from action, the only option attribute you must specify is callback, the function to call:

parser.add_option("-c", action="callback", callback=my_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
словарь дополнительных именованных аргументов, передаваемых колбэку

Как вызываются колбэкиHow callbacks are called

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

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.

Возбуждение ошибок в колбэкеRaising errors in a callback

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

Пример колбэка 1: тривиальный колбэкCallback example 1: trivial callback

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

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: проверка порядка опцийCallback example 2: check option order

Вот чуть более интересный пример: запоминать, что "-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: проверка порядка параметров (обобщённый)Callback example 3: check option order (generalized)

Если требуется повторно использовать этот колбэк для нескольких похожих опций (установить флаг, но выдать ошибку, если "-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: проверка произвольного условияCallback example 4: check arbitrary condition

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

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: фиксированное число аргументовCallback example 5: fixed arguments

Ситуация становится немного интереснее, когда определяются колбэк-опции, принимающие фиксированное количество аргументов. Указание, что колбэк-опция принимает аргументы, аналогично определению опции 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: переменное число аргументовCallback example 6: variable arguments

Дело усложняется, когда требуется, чтобы опция принимала переменное число аргументов. В этом случае необходимо написать колбэк, поскольку 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:
         # останавливаться на опциях вида --foo
         if arg[:2] == "--" and len(arg) > 2:
             break
         # останавливаться на -a, но не на -3 или -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)

Расширение optparseExtending optparse

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

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

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

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

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)

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

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

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

Это пересекающиеся множества: некоторые стандартные действия «store»: store, store_const, append и count, а стандартные действия «typed»: store, append и колбэк.

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

ACTIONS
все действия должны быть перечислены в ACTIONS
STORE_ACTIONS
«store»-действия дополнительно перечислены здесь
TYPED_ACTIONS
«typed»-действия дополнительно перечислены здесь
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 назначал тип по умолчанию 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() позаботится о правильной установке, когда это потребуется.