summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2007-04-17 20:49:35 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2007-04-17 20:49:35 +0000
commitaabb6e530b05bee9cc5c2382a308a987abd6168e (patch)
treecd937947baf100d75e679e2f6d40e3a287ffc196 /lib
parent8d7a271b8687dbcb58cac713f9e16e445d242881 (diff)
downloadsqlalchemy-aabb6e530b05bee9cc5c2382a308a987abd6168e.tar.gz
- the dialects within sqlalchemy.databases become a setuptools
entry points. loading the built-in database dialects works the same as always, but if none found will fall back to trying pkg_resources to load an external module [ticket:521]
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/databases/firebird.py8
-rw-r--r--lib/sqlalchemy/databases/mssql.py34
-rw-r--r--lib/sqlalchemy/databases/mysql.py8
-rw-r--r--lib/sqlalchemy/databases/oracle.py10
-rw-r--r--lib/sqlalchemy/databases/postgres.py20
-rw-r--r--lib/sqlalchemy/databases/sqlite.py28
-rw-r--r--lib/sqlalchemy/engine/strategies.py20
-rw-r--r--lib/sqlalchemy/engine/url.py25
8 files changed, 86 insertions, 67 deletions
diff --git a/lib/sqlalchemy/databases/firebird.py b/lib/sqlalchemy/databases/firebird.py
index 2ab88101a..4695426eb 100644
--- a/lib/sqlalchemy/databases/firebird.py
+++ b/lib/sqlalchemy/databases/firebird.py
@@ -15,9 +15,6 @@ import sqlalchemy.ansisql as ansisql
import sqlalchemy.types as sqltypes
import sqlalchemy.exceptions as exceptions
-def dbapi():
- import kinterbasdb
- return kinterbasdb
_initialized_kb = False
@@ -113,6 +110,11 @@ class FBDialect(ansisql.ANSIDialect):
self.type_conv = type_conv
self.concurrency_level= concurrency_level
+ def dbapi(cls):
+ import kinterbasdb
+ return kinterbasdb
+ dbapi = classmethod(dbapi)
+
def create_connect_args(self, url):
opts = url.translate_connect_args(['host', 'database', 'user', 'password', 'port'])
if opts.get('port'):
diff --git a/lib/sqlalchemy/databases/mssql.py b/lib/sqlalchemy/databases/mssql.py
index 41b51d12d..22fafad81 100644
--- a/lib/sqlalchemy/databases/mssql.py
+++ b/lib/sqlalchemy/databases/mssql.py
@@ -52,21 +52,6 @@ import sqlalchemy.ansisql as ansisql
import sqlalchemy.types as sqltypes
import sqlalchemy.exceptions as exceptions
-def dbapi(module_name=None):
- if module_name:
- try:
- dialect_cls = dialect_mapping[module_name]
- return dialect_cls.import_dbapi()
- except KeyError:
- raise exceptions.InvalidRequestError("Unsupported MSSQL module '%s' requested (must be adodbpi, pymssql or pyodbc)" % module_name)
- else:
- for dialect_cls in [MSSQLDialect_adodbapi, MSSQLDialect_pymssql, MSSQLDialect_pyodbc]:
- try:
- return dialect_cls.import_dbapi()
- except ImportError, e:
- pass
- else:
- raise ImportError('No DBAPI module detected for MSSQL - please install adodbapi, pymssql or pyodbc')
class MSNumeric(sqltypes.Numeric):
def convert_result_value(self, value, dialect):
@@ -331,7 +316,24 @@ class MSSQLDialect(ansisql.ANSIDialect):
self.auto_identity_insert = auto_identity_insert
self.text_as_varchar = False
self.set_default_schema_name("dbo")
-
+
+ def dbapi(cls, module_name=None):
+ if module_name:
+ try:
+ dialect_cls = dialect_mapping[module_name]
+ return dialect_cls.import_dbapi()
+ except KeyError:
+ raise exceptions.InvalidRequestError("Unsupported MSSQL module '%s' requested (must be adodbpi, pymssql or pyodbc)" % module_name)
+ else:
+ for dialect_cls in [MSSQLDialect_adodbapi, MSSQLDialect_pymssql, MSSQLDialect_pyodbc]:
+ try:
+ return dialect_cls.import_dbapi()
+ except ImportError, e:
+ pass
+ else:
+ raise ImportError('No DBAPI module detected for MSSQL - please install adodbapi, pymssql or pyodbc')
+ dbapi = classmethod(dbapi)
+
def create_connect_args(self, url):
opts = url.translate_connect_args(['host', 'database', 'user', 'password', 'port'])
opts.update(url.query)
diff --git a/lib/sqlalchemy/databases/mysql.py b/lib/sqlalchemy/databases/mysql.py
index d3a42ccdc..21f8bb398 100644
--- a/lib/sqlalchemy/databases/mysql.py
+++ b/lib/sqlalchemy/databases/mysql.py
@@ -12,9 +12,6 @@ import sqlalchemy.types as sqltypes
import sqlalchemy.exceptions as exceptions
from array import array
-def dbapi():
- import MySQLdb as mysql
- return mysql
def kw_colspec(self, spec):
if self.unsigned:
@@ -280,6 +277,11 @@ class MySQLDialect(ansisql.ANSIDialect):
def __init__(self, **kwargs):
ansisql.ANSIDialect.__init__(self, default_paramstyle='format', **kwargs)
+ def dbapi(cls):
+ import MySQLdb as mysql
+ return mysql
+ dbapi = classmethod(dbapi)
+
def create_connect_args(self, url):
opts = url.translate_connect_args(['host', 'db', 'user', 'passwd', 'port'])
opts.update(url.query)
diff --git a/lib/sqlalchemy/databases/oracle.py b/lib/sqlalchemy/databases/oracle.py
index fce59a072..f49f1d4c0 100644
--- a/lib/sqlalchemy/databases/oracle.py
+++ b/lib/sqlalchemy/databases/oracle.py
@@ -11,9 +11,6 @@ from sqlalchemy import util, sql, engine, schema, ansisql, exceptions, logging
from sqlalchemy.engine import default, base
import sqlalchemy.types as sqltypes
-def dbapi():
- import cx_Oracle
- return cx_Oracle
class OracleNumeric(sqltypes.Numeric):
@@ -172,7 +169,12 @@ class OracleDialect(ansisql.ANSIDialect):
self.ORACLE_BINARY_TYPES = [getattr(self.dbapi, k) for k in ["BFILE", "CLOB", "NCLOB", "BLOB", "LONG_BINARY", "LONG_STRING"] if hasattr(self.dbapi, k)]
else:
self.ORACLE_BINARY_TYPES = []
-
+
+ def dbapi(cls):
+ import cx_Oracle
+ return cx_Oracle
+ dbapi = classmethod(dbapi)
+
def create_connect_args(self, url):
if url.database:
# if we have a database, then we have a remote host
diff --git a/lib/sqlalchemy/databases/postgres.py b/lib/sqlalchemy/databases/postgres.py
index a93ba200c..0eca18be3 100644
--- a/lib/sqlalchemy/databases/postgres.py
+++ b/lib/sqlalchemy/databases/postgres.py
@@ -16,15 +16,6 @@ try:
except:
mxDateTime = None
-def dbapi():
- try:
- import psycopg2 as psycopg
- except ImportError, e:
- try:
- import psycopg
- except ImportError, e2:
- raise e
- return psycopg
class PGInet(sqltypes.TypeEngine):
def get_col_spec(self):
@@ -258,6 +249,17 @@ class PGDialect(ansisql.ANSIDialect):
self.use_information_schema = use_information_schema
self.paramstyle = 'pyformat'
+ def dbapi(cls):
+ try:
+ import psycopg2 as psycopg
+ except ImportError, e:
+ try:
+ import psycopg
+ except ImportError, e2:
+ raise e
+ return psycopg
+ dbapi = classmethod(dbapi)
+
def create_connect_args(self, url):
opts = url.translate_connect_args(['host', 'database', 'user', 'password', 'port'])
if opts.has_key('port'):
diff --git a/lib/sqlalchemy/databases/sqlite.py b/lib/sqlalchemy/databases/sqlite.py
index 2b7e28dfb..0222496f8 100644
--- a/lib/sqlalchemy/databases/sqlite.py
+++ b/lib/sqlalchemy/databases/sqlite.py
@@ -12,18 +12,6 @@ import sqlalchemy.engine.default as default
import sqlalchemy.types as sqltypes
import datetime,time
-def dbapi():
- try:
- from pysqlite2 import dbapi2 as sqlite
- except ImportError, e:
- try:
- from sqlite3 import dbapi2 as sqlite #try the 2.5+ stdlib name.
- except ImportError:
- try:
- sqlite = __import__('sqlite') # skip ourselves
- except ImportError:
- raise e
- return sqlite
class SLNumeric(sqltypes.Numeric):
def get_col_spec(self):
@@ -160,6 +148,20 @@ class SQLiteDialect(ansisql.ANSIDialect):
return tuple([int(x) for x in num.split('.')])
self.supports_cast = (self.dbapi is None or vers(self.dbapi.sqlite_version) >= vers("3.2.3"))
+ def dbapi(cls):
+ try:
+ from pysqlite2 import dbapi2 as sqlite
+ except ImportError, e:
+ try:
+ from sqlite3 import dbapi2 as sqlite #try the 2.5+ stdlib name.
+ except ImportError:
+ try:
+ sqlite = __import__('sqlite') # skip ourselves
+ except ImportError:
+ raise e
+ return sqlite
+ dbapi = classmethod(dbapi)
+
def compiler(self, statement, bindparams, **kwargs):
return SQLiteCompiler(self, statement, bindparams, **kwargs)
@@ -347,4 +349,4 @@ class SQLiteIdentifierPreparer(ansisql.ANSIIdentifierPreparer):
super(SQLiteIdentifierPreparer, self).__init__(dialect, omit_schema=True)
dialect = SQLiteDialect
-poolclass = pool.SingletonThreadPool
+dialect.poolclass = pool.SingletonThreadPool
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index ba9b0968a..ed31743d8 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -41,27 +41,26 @@ class DefaultEngineStrategy(EngineStrategy):
# create url.URL object
u = url.make_url(name_or_url)
- # get module from sqlalchemy.databases
- module = u.get_module()
+ dialect_cls = u.get_dialect()
dialect_args = {}
# consume dialect arguments from kwargs
- for k in util.get_cls_kwargs(module.dialect):
+ for k in util.get_cls_kwargs(dialect_cls):
if k in kwargs:
dialect_args[k] = kwargs.pop(k)
dbapi = kwargs.pop('module', None)
if dbapi is None:
dbapi_args = {}
- for k in util.get_func_kwargs(module.dbapi):
+ for k in util.get_func_kwargs(dialect_cls.dbapi):
if k in kwargs:
dbapi_args[k] = kwargs.pop(k)
- dbapi = module.dbapi(**dbapi_args)
+ dbapi = dialect_cls.dbapi(**dbapi_args)
dialect_args['dbapi'] = dbapi
# create dialect
- dialect = module.dialect(**dialect_args)
+ dialect = dialect_cls(**dialect_args)
# assemble connection arguments
(cargs, cparams) = dialect.create_connect_args(u)
@@ -77,7 +76,7 @@ class DefaultEngineStrategy(EngineStrategy):
raise exceptions.DBAPIError("Connection failed", e)
creator = kwargs.pop('creator', connect)
- poolclass = kwargs.pop('poolclass', getattr(module, 'poolclass', poollib.QueuePool))
+ poolclass = kwargs.pop('poolclass', getattr(dialect_cls, 'poolclass', poollib.QueuePool))
pool_args = {}
# consume pool arguments from kwargs, translating a few of the arguments
@@ -158,17 +157,16 @@ class MockEngineStrategy(EngineStrategy):
# create url.URL object
u = url.make_url(name_or_url)
- # get module from sqlalchemy.databases
- module = u.get_module()
+ dialect_cls = u.get_dialect()
dialect_args = {}
# consume dialect arguments from kwargs
- for k in util.get_cls_kwargs(module.dialect):
+ for k in util.get_cls_kwargs(dialect_cls):
if k in kwargs:
dialect_args[k] = kwargs.pop(k)
# create dialect
- dialect = module.dialect(**dialect_args)
+ dialect = dialect_cls(**dialect_args)
return MockEngineStrategy.MockConnection(dialect, executor)
diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py
index faa0ffc11..c5ad90ee9 100644
--- a/lib/sqlalchemy/engine/url.py
+++ b/lib/sqlalchemy/engine/url.py
@@ -69,19 +69,28 @@ class URL(object):
s += '?' + "&".join(["%s=%s" % (k, self.query[k]) for k in keys])
return s
- def get_module(self):
- """Return the SQLAlchemy database module corresponding to this URL's driver name."""
+ def get_dialect(self):
+ """Return the SQLAlchemy database dialect class corresponding to this URL's driver name."""
+ dialect=None
if self.drivername == 'ansi':
import sqlalchemy.ansisql
- return sqlalchemy.ansisql
-
+ return sqlalchemy.ansisql.dialect
+
try:
- return getattr(__import__('sqlalchemy.databases.%s' % self.drivername).databases, self.drivername)
+ module=getattr(__import__('sqlalchemy.databases.%s' % self.drivername).databases, self.drivername)
+ dialect=module.dialect
except ImportError:
if sys.exc_info()[2].tb_next is None:
- raise exceptions.ArgumentError('unknown database %r' % self.drivername)
- raise
-
+ import pkg_resources
+ for res in pkg_resources.iter_entry_points('sqlalchemy.databases'):
+ if res.name==self.drivername:
+ dialect=res.load()
+ else:
+ raise
+ if dialect is not None:
+ return dialect
+ raise ImportError('unknown database %r' % self.drivername)
+
def translate_connect_args(self, names):
"""Translate this URL's attributes into a dictionary of connection arguments.