API-спецификация баз данных языка Python, версия 2.0 (Database API Specification 2.0)
Дата: 20.11.2000
Python.org
Этот API был определен для поощрения сходства между модулями Python, используемыми для доступа к базам данных. Таким образом мы надеемся достичь соответствия, которое приведет к более понятным модулям, коду, который в целом легче переносим между базами данных и более широкому спектру возможностей языка Python по доступу к базам данных.
Спецификация интерфейса состоит из нескольких разделов:
Интерфейс модуля
Объекты соединения
Объекты курсора
Объекты типа и конструкторы
Советы по реализации
Основные изменения в версии 2.0 относительно версии 1.0
Комментарии и вопросы по этой спецификации могут быть направлены в адрес Специальной группы по доступу к базам данных из Python.
За дополнительной информацией о доступе к базам данных из Python и о имеющихся пакетах обращайтесь к Руководству по базам данных на www.python.org.
Этот документ описывает Python Database API Specification 2.0. Предыдущая версия 1.0 все еще доступна для справки. Поощряется использование последней версии спецификации в качестве основы для нового интерфейса программистами, пишущими пакеты.
Интерфейс модуля
Доступ к базе данных реализуется с помощью объектов соединения (connection objects). Модуль должен предоставлять для них следующий конструктор:
connect(параметры...)
Должны быть определены следующие глобальные переменные модуля:
apilevel
threadsafety
paramstyle
Модуль должен обеспечивать всю информацию об ошибках с помощью следующих исключений или их подклассов:
Warning
Error
InterfaceError
DatabaseError
DataError
OperationalError
IntegrityError
InternalError
ProgrammingError
NotSupportedError
Вот схема наследования исключений:
StandardError
|__Warning
|__Error
|__InterfaceError
|__DatabaseError
|__DataError
|__OperationalError
|__IntegrityError
|__InternalError
|__ProgrammingError
|__NotSupportedError
Примечание: Значения этих исключений не определены. Они должны отчетливо подсказывать пользователю, что именно пошло не так.
Объекты соединения
Объекты соединения должны реагировать на следующие вызовы:
close()
commit()
rollback()
cursor()
Объекты курсора
Эти объекты представляют курсор базы данных, используемый для управления контекстом операции выборки.
Объекты курсора должны поддерживать следующие методы и атрибуты:
description
rowcount
callproc(имя процедуры[,параметры])
close()
execute(операция[,параметры])
executemany(операция, seq_of_parameters)
fetchone()
fetchmany([размер=cursor.arraysize])
fetchall()
nextset().
arraysize
setinputsizes(sizes)
setoutputsize(размер[,столбец])
Объекты типа и конструкторы
Многие базы данных требуют входных данных в определенном формате для привязки к input-параметрам операций. Например, если данные предназначены для столбца типа DATE, они должен быть подготовлены для базы данных в определенном строковом формате. Такие же проблемы существуют для столбцов "Row ID" или больших бинарных элементов (например, blob'ов или столбцов RAW). Это представляет проблему для Python, поскольку параметры метода executeXXX() не типизированы. Когда модуль базы данных видит строковый объект Python, он не знает, нужно ли его привязывать как простой символьный столбец (CHAR), как необработанный бинарный элемент (BINARY) или как дату (DATE).
Для преодоления этой проблемы модуль должен обеспечивать описанные ниже конструкторы для создания объектов, которые могут хранить специальные значения. Когда такой объект передется методам курсора, модуль может определить правильный тип входного параметра и привязать его соответствующим образом.
Атрибут объекта курсора description возвращает информацию о каждом из столбцов результата запроса. Код типа type_code должен быть проверен на равенство одному из Объектов типа, описанных ниже. Объекты типа могут быть равны более чем одному коду типа (например, DATETIME может быть равен кодам типа для столбцов даты, времени и временной метки; подробно см. Советы по реализации, данные ниже).
Модуль экспортирует следующие конструкторы и одноэлементные множества:
Date(год,месяц,день)
Time(час,минута,секунда)
Timestamp(год,месяц,день,час,минута,секунда)
DateFromTicks(отсчеты)
TimeFromTicks(отсчеты)
TimestampFromTicks(отсчеты)
BINARY(строка)
STRING
BINARY
NUMBER
DATETIME
ROWID
NULL-значения SQL представляются с помощью None при вводе и выводе.
Примечание: Использование отсчетов Unix при взаимодействии с базой данных может создать проблемы из-за ограниченности спектра описываемых ими дат.
Советы по реализации
- Предпочтительными типами для объектов дата/время являются те, что определены в пакете mxDateTime . Он обеспечивает необходимые конструкторы и методы как на уровне Python, так и Cи.
- Предпочтительным типом объекта для бинарных объектов являются типы буферов, доступные в стандартном Python, начиная с версии 1.5.2. За дополнительной информацией обращайтесь к документации по Python. Для информации по интерфейсу к Си взгляните в
Include/bufferobject.h и Objects/bufferobject.c в исходниках Python.
- Вот пример реализации конструкторов даты/времени, базирующихся на отсчетах Unix, делегирующих работу общим конструкторам:
import time
def DateFromTicks(ticks):
return apply(Date,time.localtime(ticks)[:3])
def TimeFromTicks(ticks):
return apply(Time,time.localtime(ticks)[3:6])
def TimestampFromTicks(ticks):
return apply(Timestamp,time.localtime(ticks)[:6])
- Этот класс языка Python позволяет реализовать вышеприведенные объекты типа даже несмотря на то, что поле кода типа содержит множество значений для одного объекта типа:
class DBAPITypeObject:
def __init__(self,*values):
self.values = values
def __cmp__(self,other):
if other in self.values:
return 0
if other < self.values:
return 1
else:
return -1
Результирующий объект типа при сравнении на равенство оказывается равным всем значениям, переданным конструктору.
- Вот фрагмент кода языка Python, реализующего иерархию исключений, приведенную выше:
import exceptions
class Error(exceptions.StandardError):
pass
class Warning(exceptions.StandardError):
pass
class InterfaceError(Error):
pass
class DatabaseError(Error):
pass
class InternalError(DatabaseError):
pass
class OperationalError(DatabaseError):
pass
class ProgrammingError(DatabaseError):
pass
class IntegrityError(DatabaseError):
pass
class DataError(DatabaseError):
pass
class NotSupportedError(DatabaseError):
pass
В языке Си для создания объектов исключений вы можете использовать API PyErr_NewException(fullname, base, NULL).
Основные изменения в версии 2.0 относительно версии 1.0
Python Database API 2.0 вводит несколько значительных изменений относительно версии 1.0. Ввиду того, что некоторые из этих изменений приведут к нарушению работы существующих скриптов, основанных на DB API 1.0, старший номер версии был увеличен для отражения этого изменения.
Вот наиболее важные изменения между версиями 1.0 и 2.0:
- Отпала необходимость в отдельном модуле dbi, эта функция встроена в сам интерфейс модуля.
- Были добавлены новые конструкторы и Объекты типа для значений дата/время, Объекты типа RAW были переименованы в BINARY. Полученный набор должен охватывать все основные типы данных, обычно имеющиеся в современных базах данных SQL.
- Были добавлены новые константы (apilevel, threadlevel, paramstyle) и методы (executemany, nextset) для обеспечения лучшей привязки к базам данных.
- Теперь ясно определена семантика .callproc(), необходимой для вызова хранимых процедур.
- Изменено определение возвращаемого значения .execute(). Ранее возвращаемое значение основывалось на типе предложения SQL (что было крайне трудно правильно реализовать) - сейчас оно не определено; пользуйтесь вместо него более гибким атрибутом .rowcount. Модули свободны в возвращении значений в старом виде, однако это больше не предписывается спецификацией и должно считаться зависящим от интерфейса базы данных.
- Исключения, основанные на классах, были встроены в спецификацию. Реализаторы модуля свободны расширить схему исключений, определенную в этой спецификации, путем наследования от описанных классов исключений.
Открытые вопросы
Несмотря на то, что спецификация версии 2.0 прояснила многие из вопросов, оставленных открытыми в версии 1.0, остается еще несколько проблем:
- Определить подходящее значение возврата .nextset() для случая наличия нового результирующего множества.
- Создать числовой тип с фиксированной точкой для использования в качестве не имеющего потерь точности денежного и десятичного форматов.
Сноски
1. В качестве руководящего указания параметры конструктора соединения должны быть реализованы как ключевые параметры для более интуитивного использования и согласно следующей последовательности параметров:
dsn |
= Источник данных в виде строки |
|
user |
= Имя пользователя в виде строки |
(необязательно) |
password |
= Пароль в виде строки |
(необязательно) |
host |
= Имя хоста |
(необязательно) |
database |
= Имя базы данных |
(необязательно) |
Например, соединение может выглядеть следующим образом:
connect(dsn='myhost:MYDB',user='guido',password='234$')
2. Реализаторы модуля должны отдавать предпочтение 'numeric', 'named' и 'pyformat' перед другими форматами, так как это предполагает большую четкость и гибкость.
3. Если база данных не поддерживает функцию, необходимую для метода, интерфейс должен возбуждать исключение при попытке использования этого метода.
Предпочтительный подход заключается в отказе от реализации такого метода, тем самым приводя к генерации языком Python исключения AttributeError в случае, если запрашивается этот метод. Это позволяет программисту проверить возможности базы данных, используя стандартную функцию hasattr().
Для некоторых динамически конфигурируемых интерфейсов может не годиться необходимость динамического создания метода. Эти интерфейсы в таком случае должны вызывать исключение NotSupportedError для указания на невозможность исполнения отката, когда метод уже вызван.
4. Интерфейс базы данных может поддержать именованные курсоры путем разрешения строкового аргумента для метода. Это свойство не является частью спецификации, поскольку оно усложняет семантику методов .fetchXXX().
5. Модуль будет использовать метод __getitem__ объекта параметров для отображения как позиций (целых чисел), так и имен (строк) в значения параметров. Это позволяет использовать в качестве входных величин как последовательности, так и словари.
Термин "привязка" относится к процессу привязки входного значения к буферу выполнения базы данных. В практических терминах это означает, что входное значение напрямую используется в качестве значения в операции. От клиента не должно требоваться "выделение" ("escaping") этого значения таким образом, чтобы его можно было использовать - значение должно быть равно действительному значению из базы данных.
6. Заметьте, что интерфейс может реализовывать выборку строк с использованием массивов и другие виды оптимизации. Нет гарантии, что обращение к этому методу сдвинет соответствующий курсор вперед только на одну строку.
7. Атрибут rowcount может быть запрограммирован способом, динамически обновляющим его значение. Это может быть полезно для баз данных, возвращающих осмысленные значения rowcount только после первого вызова метода .fetchXXX().
|