Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

[ Россум, Дрейк, Откидач ] Язык программирования Python

.pdf
Скачиваний:
295
Добавлен:
25.04.2014
Размер:
1.5 Mб
Скачать

28.1. rfc822 — обработка заголовков электронных писем

371

отображений методов (has_key(), keys(), values(), items(), get()). Сопоставление имен заголовков производится независимо от используемого регистра букв, то есть выражения m[’From’], m[’from’] и m[’FROM’] полностью эквивалентны. Значением заголовка считается текст после двоеточия в первой строке заголовка плюс текст из строк продолжения с убранными символами пропуска в начале и конце. Кроме того, эти объекты имеют следующие методы и атрибуты данных:

rewindbody()

Перемещает указатель на начало сообщения. Этот метода работает только в том случае, если используемый файловый объект имеет методы tell() и seek().

isheader(line)

Возвращает канонизированное имя заголовка, если line является соответствующим RFC 822 заголовком, иначе возвращает None (предполагая, что анализ должен быть остановлен в этом месте и строка должна быть помещена обратно в поток). Вы можете переопределить этот метод в производном классе для обеспечения поддержки расширенных форматов заголовков.

islast(line)

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

iscomment(line)

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

getallmatchingheaders(name)

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

getfirstmatchingheader(name)

Возвращает список строк, составляющих первый заголовок с именем name. Если нет заголовков с указанным именем, возвращает None.

getrawheader(name)

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

getheader(name [, default])

Псевдоним стандартного метода get() отображений.

372

Глава 28. Поддержка форматов, используемых в Internet

getaddr(name)

Возвращает кортеж из двух строк (возможно пустых) с полным именем и адресом электронной почты, взятых из первого заголовка с именем name. Если нет заголовков с указанным именем, возвращает ‘(None, None)’. Например, если первый заголовок, сохраненный объектом m, содержит строку ’jack@cwi.nl (Jack Jansen)’ (или ’Jack Jansen <jack@cwi.nl>’), m.getaddr(’From’) даст пару ‘(’Jack Jansen’, ’jack@cwi.nl’)’.

getaddrlist(name)

Работает аналогично методу getaddr(), но обрабатывает заголовок (или заголовки) с именем name как содержащий список адресов (например, заголовок ‘To’ или серия заголовков ‘Cc’) и возвращает список кортежей с полным именем и адресом электронной почты. Если нет заголовков с указанным именем, возвращает пустой список.

getdate(name)

Анализирует первый заголовок с именем name на предмет содержания даты и времени и возвращает кортеж из девяти элементов (см. описание функции parsedate()) или None, если нет заголовков с указанным именем или первый такой заголовок не содержит даты (не может быть обработан функцией parsedate()).

getdate_tz(name)

Работает аналогично методу getdate(), но возвращает кортеж из десяти элементов; последний элемент равен сдвигу в секундах часового пояса относительно универсального времени (см. описание функции parsedate_tz()) или None.

headers

Список всех строк заголовков в порядке их следования во входном файле. Каждая строка содержит завершающий символ перехода на новую строку. Разделительная строка (сигнализирующая конец заголовков) в этот список не включается.

fp

Файловый (или подобный) объект, который был использован при инициализации. Может быть использован для чтения содержимого сообщения.

Экземпляры класса AddressList (обозначенные ниже как a и b) по поведению схожи с множествами (см. раздел 9.7.3) и поддерживают следующие операции:

len(a)

Количество адресов в списке.

str(a)

Канонизированное строковое представление списка (через запятую) адресов. Каждый адрес представляется в виде ‘"name" <e_mail>’.

a + b

Дает экземпляр класса AddressList с адресами из обоих списков, но без дубликатов (объединение множеств).

28.2. mimetools — обработка сообщений в формате MIME

373

a - b

Дает экземпляр класса AddressList с адресами, которые содержаться в списке a, но не содержаться в списке b (разница множеств).

Кроме того, экземпляры класса AddressList имеют один публичный атрибут:

addresslist

Список кортежей (по одному на каждый адрес) из двух строк: канонизированного имени и электронного адреса.

28.2 mimetools — обработка сообщений в формате MIME

Этот модуль определяет класс Message, производный от rfc822.Message, а также набор функций, полезных при обработке сообщений в формате MIME (Multipurpose Internet Mail Extensions, многоцелевые расширения электронной почты).

Message(fp [, seekable])

Этот класс является производным от класса rfc822.Message и определяет несколько дополнительный методов, описанных ниже. Аргументы имеют такое же значение, как и для класса rfc822.Message (см. описание модуля rfc822).

choose_boundary()

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

decode(input, output, encoding)

Считывает данные в MIME-кодировке encoding из потока input и записывает раскодированные данные в поток output. Аргумент encoding может иметь одно из следующих значений: ’base64’, ’quoted-printable’, ’uuencode’

(для большей совместимости воспринимаются также ’x-uuencode’, ’uue’ и ’x-uue’), ’7bit’ или ’8bit’.

encode(input, output, encoding)

Считывает данные из потока input, преобразует в MIME-кодировку encoding и записывает в поток output. Поддерживаемые значения аргумента encoding такие же, как и для функции decode().

copyliteral(input, output)

Считывает строки текста из потока input (до конца файла) и записывает их в поток output.

374

Глава 28. Поддержка форматов, используемых в Internet

copybinary(input, output)

Считывает блоки двоичных данных из потока input (до конца файла) и записывает их в поток output. В текущих реализациях размер блоков фиксирован и равен 8192 байт.

Экземпляры класса Message помимо унаследованных от rfc822.Message имеют следующие методы:

getplist()

Возвращает список параметров (строк) из заголовка ‘content-type’. Для параметров вида ‘name=value’ имя name преобразуется к нижнему регистру. Например, если сообщение содержит заголовок ‘Content-type: text/html; spam=1; Spam=2; Spam’, метод getplist() вернет список [’spam=1’, ’spam=2’, ’Spam’].

getparam(name)

Возвращает значение (value) первого параметра вида ‘name=value’ с указанным именем (сопоставление производится без учета регистра букв) из заголовка ‘content-type’. Если значение помещено в двойные кавычки ‘"value"’ или угловые скобки ‘<value>’, то они удаляются.

getencoding()

Возвращает строку с кодировкой сообщения, указанного в заголовке ‘content- transfer-encoding’. Если сообщение не содержит такого заголовка, возвращает ’7bit’. Буквы в возвращаемой строке приводятся к нижнему регистру.

gettype()

Возвращает тип содержимого сообщения в виде строки ‘ПУОПЧОПК_ФЙР/РПДФЙР’, указанный в заголовке content-type. Если сообщение не содержит такого заголовка, возвращает ’text/plain’. Буквы в возвращаемой строке приведены к нижнему регистру.

getmaintype()

Возвращает строку с основным типом содержимого сообщения, указанного в заголовке content-type. Если сообщение не содержит такого заголовка, возвращает ’text’. Буквы в возвращаемой строке приведены к нижнему регистру.

getsubtype()

Возвращает строку с подтипом содержимого сообщения, указанного в заголовке content-type. Если сообщение не содержит такого заголовка, возвращает ’plain’. Буквы в возвращаемой строке приведены к нижнему регистру.

28.3MimeWriter — средства для записи в формате MIME

Этот модуль определяет класс MimeWriter, реализующий запись сообщений, состоящих из нескольких частей, в MIME-формате:

28.3. MimeWriter — средства для записи в формате MIME

375

MimeWriter(fp)

Экземпляры этого класса реализуют запись в MIME-формате в поток fp (файловый или подобный объект).

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

addheader(name, value [, prefix])

Добавляет к сообщению заголовок name со значением value. Необязательный аргумент prefix указывает место, в которое заголовок будет добавлен: 0 (используется по умолчанию) — добавить в коней, 1 — вставить в начало.

flushheaders()

При вызове этого метода все накопленные (с помощью метода addheader()) заголовки записываются в поток и забываются. Такая операция может быть полезна, если Вы не собираетесь записывать основную часть (тело) сообщения, например, для блоков типа ‘message/rfc822’, которые иногда используется для представления информации, аналогичной заголовкам.

startbody(ctype [, plist [, prefix]])

Возвращает объект, аналогичный файловому, который может быть использован для записи основной части (тела) сообщения. Аргумент ctype указывает значение, которое будет использоваться в заголовке ‘content-type’ (тип данных). Если задан аргумент plist, он должен быть списком пар вида ‘(name, value)’, которые будут использованы в качестве дополнительных параметров в заголовке ‘contenttype’. Назначение аргумента prefix такое же, как и для метода addheader(), но по умолчанию он равен 0 (добавить в начало).

startmultipartbody(subtype [, boundary [, plist [, prefix]]])

Возвращает объект, аналогичный файловому, который может быть использован для записи тела сообщения, состоящего из нескольких частей. Аргумент указывает подтип сообщения типа ‘multipart’, boundary может быть использован для указания дружественного разделителя частей (по умолчанию используется mimetools.choose_boundary()), список plist задает дополнительные параметры заголовка ‘content-type’. Аргумент prefix имеет такое же значение, как и для метода startbody(). Подчасти должны создаваться с помощью метода nextpart().

nextpart()

Возвращает новый экземпляр класса MimeWriter, представляющий часть в сообщении типа ‘multipart/*’. Этот объект может быть использован, в том числе, и для вложенных сообщений, состоящих из нескольких частей. Перед использованием метода nextpart() должен быть вызван метод startmultipartbody().

lastpart()

Это метод всегда должен быть использован после записи сообщений, состоящих из нескольких частей (типа ‘multipart/*’).

376

Глава 28. Поддержка форматов, используемых в Internet

28.4multifile — чтение сообщений, состоящих из нескольких частей

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

MultiFile(fp [, seekable])

Создает и возвращает объект, реализующий чтение частей текста. Аргумент fp должен быть файловым (или подобным) объектом, из которого будет производиться чтение исходного текста. На самом деле достаточно наличия у fp методов readline(), seek() и tell(). Последние два метода требуются для обеспечения произвольного доступа к частям текста. Если задан и является ложью аргумент seekable, методы seek() и tell() объекта fp использоваться не будут.

Error

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

С точки зрения реализации класса MultiFile исходный текст состоит из трех видов строк: данных, разделителей частей и метки конца. Этот класс приспособлен к обработке сообщений, части которых состоят из несколько вложенных частей. В каждом таком случае должен быть свой шаблон для разделительных строк и метки конца.

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

push(str)

Записывает в стек разделительную строку. Если эта строка, соответствующим образом выделенная, будет найдена во входном потоке, она будет интерпретирована как разделитель частей или метка конца. Все последующие попытки чтения из экземпляра класса MultiFile будут возвращать пустую строку до тех пор, пока разделительная строка не будет удалена из стека с помощью метода pop() или ее использование не будет повторно разрешено с помощью метода next().

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

readline()

Считывает и возвращает очередную строку из текущей части. При достижении разделителя частей или метки конца возвращает пустую строку. Если считываемая строка удовлетворяет другому разделителю в стеке или поток с исходным текстом выдает конец файла (при непустом стеке), генерирует исключение Error.

28.4. multifile — чтение сообщений, состоящих из нескольких . . .

377

readlines()

Возвращает список всех оставшихся строк для данной части.

read()

Считывает и возвращает все оставшиеся данные для текущей части.

next()

Считывает строки до конца текущей части и, если достигнута метка конца, возвращает 0, в противном случае переходит к следующей части (разрешает повторное использование разделителя на вершине стека) и возвращает 1.

pop()

Удаляет с вершины стека разделительную строку.

seek(pos [, whence])

Перемещает указатель по текущей части. Аргументы имеют такое же значение, как и для метода seek() файловых объектов (см. раздел 11.7).

tell()

Возвращает текущую позицию в текущей части.

is_data(str)

Возвращает 1, если строка str точно не является разделителем или меткой конца (то есть является строкой с данными), иначе (если строка может быть разделителем или меткой конца) возвращает 0. Вы можете переопределить этот метод в производном классе, исходная реализация проверяет наличие ‘--’ в начале строки (для формата MIME).

Этот метод предназначен для быстрой проверки: если он будет всегда возвращать 0, это лишь замедлит обработку, но не приведет к ошибкам.

section_divider(str)

Преобразует разделительную строку str (в том виде, в котором она записывается

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

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

end_marker(str)

Преобразует разделительную строку str (в том виде, в котором она записывается

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

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

Кроме того, экземпляры класса MultiFile имеют два публичных атрибута дан-

ных:

378

Глава 28. Поддержка форматов, используемых в Internet

level

Уровень вложенности текущей части.

last

Является истиной (1), если последний разделитель являлся меткой конца.

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

import mimetools import multifile import StringIO

def extract_mime_part_matching(stream, mimetype):

msg = mimetools.Message(stream) msgtype = msg.gettype()

params = msg.getplist()

data = StringIO.StringIO()

if msgtype.startswith(’multipart/’):

file = multifile.MultiFile(stream) file.push(msg.getparam(’boundary’)) while file.next():

submsg = mimetools.Message(file) try:

data = StringIO.StringIO() mimetools.decode(file, data,

submsg.getencoding())

except ValueError: continue

if submsg.gettype() == mimetype: break

file.pop()

return data.getvalue()

28.5 xdrlib — представление данных в формате XDR

Модуль xdrlib предоставляет средства для работы с данными в формате XDR (eXternal Data Representation, аппаратно-независимое представление данных) в соответствии с RFC 10141 и поддерживает большинство типов данных, описанных в стандарте. Другие

1Формат XDR разработан фирмой Sun Microsystems в 1987 году, новая версия формата описана в RFC 1832.

28.5. xdrlib — представление данных в формате XDR

379

(менее переносимые) способы получения представления объектов описаны в главе 20. Модуль определяет два класса: для упаковки данных в XDR-представление и для их распаковки.

Packer()

Экземпляры этого класса реализуют упаковку объектов в XDR-представление.

Unpacker(data)

Экземпляры этого класса позволяют получить объекты из их XDR-представления, заданного в строке (или другом объекте, имеющем интерфейс буфера) data.

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

get_buffer()

Возвращает текущее содержимое буфера с упакованными данными в виде строки (данные их буфера не удаляются).

reset()

Очищает буфер.

pack_uint(value) pack_int(value) pack_enum(value) pack_bool(value) pack_uhyper(value) pack_hyper(value) pack_float(value) pack_double(value)

Записывают в буфер XDR-представление данных value соответствующих простых типов.

pack_fstring(n, s)

pack_fopaque(n, s)

Записывают в буфер XDR-представление строки s фиксированной длины n. Заметим, что длина строки не сохраняется в представлении. Если необходимо, строка дополняется нулевыми байтами для обеспечения выравнивания к 4 байтам.

pack_string(s) pack_opaque(s)

pack_bytes(s)

Записывают в буфер XDR-представление строки s переменной длины (сначала упаковывается длина строки в виде беззнакового целого, затем сама строка).

pack_list(list, pack_item)

Записывают в буфер XDR-представление гомогенной последовательности list,

380

Глава 28. Поддержка форматов, используемых в Internet

длина которой заранее неизвестна. Для каждого элемента последовательности сначала упаковывается 1 (как беззнаковое целое), затем значение элемента, с помощью метода (функции) pack_item. По достижении конца списка упаковывается 0 (как беззнаковое целое).

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

import xdrlib

p = xdrlib.Packer() p.pack_list([1, 2, 3], p.pack_int)

pack_farray(n, array, pack_item)

Записывают в буфер XDR-представление гомогенной последовательности array фиксированной длины n. Длина последовательности не сохраняется, но, если указанная длина последовательности не равна len(array), генерируется исключение ValueError. Для упаковки каждого элемента используется метод (функция) pack_item.

pack_array(array, pack_item)

Записывают в буфер XDR-представление гомогенной последовательности array переменной длиной. Сначала сохраняется длина последовательности, затем, с помощью метода (функции) pack_item упаковываются элементы последовательности.

Экземпляры класса Unpacker предоставляют методы для выполнения обратного преобразования:

reset(data)

Устанавливает буфер с упакованными данными равным строке data.

get_position()

Возвращает текущую позицию в буфере.

set_position(pos)

Устанавливает указатель на позицию pos в буфере. Будьте осторожны, используя этот метод.

get_buffer()

Возвращает текущее значение буфера с упакованными данными в виде строки.

done()

Указывает на завершение распаковки данных. Генерирует исключение, если не все данные были распакованы.