summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-03-15 13:08:31 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2010-03-15 13:08:31 -0400
commit5dcc32fd5a81c41b50bc35573d190a60a344c3c6 (patch)
tree10b57e17f0a724b63c9ae122d60b7036c50029df /lib
parentb3ba365eea4984882f6f5f71aa97ac454bc7d96d (diff)
downloadsqlalchemy-5dcc32fd5a81c41b50bc35573d190a60a344c3c6.tar.gz
- The visit_pool() method of Dialect is removed, and replaced with
on_connect(). This method returns a callable which receives the raw DBAPI connection after each one is created. The callable is assembled into a first_connect/connect pool listener by the connection strategy if non-None. Provides a simpler interface for dialects.
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/connectors/mxodbc.py7
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py26
-rw-r--r--lib/sqlalchemy/dialects/postgresql/psycopg2.py20
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py28
-rw-r--r--lib/sqlalchemy/engine/base.py33
-rw-r--r--lib/sqlalchemy/engine/default.py14
-rw-r--r--lib/sqlalchemy/engine/strategies.py12
-rw-r--r--lib/sqlalchemy/test/engines.py19
8 files changed, 103 insertions, 56 deletions
diff --git a/lib/sqlalchemy/connectors/mxodbc.py b/lib/sqlalchemy/connectors/mxodbc.py
index 49c5a7329..a646473fb 100644
--- a/lib/sqlalchemy/connectors/mxodbc.py
+++ b/lib/sqlalchemy/connectors/mxodbc.py
@@ -26,14 +26,13 @@ class MxODBCConnector(Connector):
raise ImportError, "Unrecognized platform for mxODBC import"
return module
- def visit_pool(self, pool):
- def connect(conn, rec):
+ def on_connect(self):
+ def connect(conn):
conn.stringformat = self.dbapi.MIXED_STRINGFORMAT
conn.datetimeformat = self.dbapi.PYDATETIME_DATETIMEFORMAT
#conn.bindmethod = self.dbapi.BIND_USING_PYTHONTYPE
#conn.bindmethod = self.dbapi.BIND_USING_SQLTYPE
-
- pool.add_listener({'connect':connect})
+ return connect
def create_connect_args(self, url):
""" Return a tuple of *args,**kwargs for creating a connection.
diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py
index 7d4cbbbd8..cbd92ccfe 100644
--- a/lib/sqlalchemy/dialects/postgresql/base.py
+++ b/lib/sqlalchemy/dialects/postgresql/base.py
@@ -600,21 +600,19 @@ class PGDialect(default.DefaultDialect):
if not self.supports_native_enum:
self.colspecs = self.colspecs.copy()
del self.colspecs[ENUM]
-
- def visit_pool(self, pool):
- if self.isolation_level is not None:
- class SetIsolationLevel(object):
- def __init__(self, isolation_level):
- self.isolation_level = isolation_level
-
- def connect(self, conn, rec):
- cursor = conn.cursor()
- cursor.execute("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL %s"
- % self.isolation_level)
- cursor.execute("COMMIT")
- cursor.close()
- pool.add_listener(SetIsolationLevel(self.isolation_level))
+ def on_connect(self):
+ if self.isolation_level is not None:
+ def connect(conn):
+ cursor = conn.cursor()
+ cursor.execute("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL %s"
+ % self.isolation_level)
+ cursor.execute("COMMIT")
+ cursor.close()
+ return connect
+ else:
+ return None
+
def do_begin_twophase(self, connection, xid):
self.do_begin(connection.connection)
diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
index 48349834d..c239a3ee0 100644
--- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py
+++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py
@@ -179,20 +179,18 @@ class PGDialect_psycopg2(PGDialect):
psycopg = __import__('psycopg2')
return psycopg
- _unwrap_connection = None
-
- def visit_pool(self, pool):
+ def on_connect(self):
+ base_on_connect = super(PGDialect_psycopg2, self).on_connect()
if self.dbapi and self.use_native_unicode:
extensions = __import__('psycopg2.extensions').extensions
- def connect(conn, rec):
- if self._unwrap_connection:
- conn = self._unwrap_connection(conn)
- if conn is None:
- return
+ def connect(conn):
extensions.register_type(extensions.UNICODE, conn)
- pool.add_listener({'first_connect': connect, 'connect':connect})
- super(PGDialect_psycopg2, self).visit_pool(pool)
-
+ if base_on_connect:
+ base_on_connect(conn)
+ return connect
+ else:
+ return base_on_connect
+
def create_connect_args(self, url):
opts = url.translate_connect_args(username='user')
if 'port' in opts:
diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py
index 5bcf90151..dfc09f025 100644
--- a/lib/sqlalchemy/dialects/sqlite/base.py
+++ b/lib/sqlalchemy/dialects/sqlite/base.py
@@ -360,21 +360,21 @@ class SQLiteDialect(default.DefaultDialect):
# hypothetical driver ?)
self.native_datetime = native_datetime
- def visit_pool(self, pool):
+ def on_connect(self):
if self.isolation_level is not None:
- class SetIsolationLevel(object):
- def __init__(self, isolation_level):
- if isolation_level == 'READ UNCOMMITTED':
- self.isolation_level = 1
- else:
- self.isolation_level = 0
-
- def connect(self, conn, rec):
- cursor = conn.cursor()
- cursor.execute("PRAGMA read_uncommitted = %d" % self.isolation_level)
- cursor.close()
- pool.add_listener(SetIsolationLevel(self.isolation_level))
-
+ if self.isolation_level == 'READ UNCOMMITTED':
+ isolation_level = 1
+ else:
+ isolation_level = 0
+
+ def connect(conn):
+ cursor = conn.cursor()
+ cursor.execute("PRAGMA read_uncommitted = %d" % isolation_level)
+ cursor.close()
+ return connect
+ else:
+ return None
+
def table_names(self, connection, schema):
if schema is not None:
qschema = self.identifier_preparer.quote_identifier(schema)
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index fa0059130..095f7a960 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -169,6 +169,7 @@ class Dialect(object):
Given a :class:`~sqlalchemy.engine.url.URL` object, returns a tuple
consisting of a `*args`/`**kwargs` suitable to send directly
to the dbapi's connect function.
+
"""
raise NotImplementedError()
@@ -183,6 +184,7 @@ class Dialect(object):
The returned result is cached *per dialect class* so can
contain no dialect-instance state.
+
"""
raise NotImplementedError()
@@ -192,6 +194,13 @@ class Dialect(object):
Allows dialects to configure options based on server version info or
other properties.
+
+ The connection passed here is a SQLAlchemy Connection object,
+ with full capabilities.
+
+ The initalize() method of the base dialect should be called via
+ super().
+
"""
pass
@@ -204,6 +213,12 @@ class Dialect(object):
properties from the database. If include_columns (a list or
set) is specified, limit the autoload to the given column
names.
+
+ The default implementation uses the
+ :class:`~sqlalchemy.engine.reflection.Inspector` interface to
+ provide the output, building upon the granular table/column/
+ constraint etc. methods of :class:`Dialect`.
+
"""
raise NotImplementedError()
@@ -458,8 +473,22 @@ class Dialect(object):
raise NotImplementedError()
- def visit_pool(self, pool):
- """Executed after a pool is created."""
+ def on_connect(self):
+ """return a callable which sets up a newly created DBAPI connection.
+
+ The callable accepts a single argument "conn" which is the
+ DBAPI connection itself. It has no return value.
+
+ This is used to set dialect-wide per-connection options such as isolation
+ modes, unicode modes, etc.
+
+ If a callable is returned, it will be assembled into a pool listener
+ that receives the direct DBAPI connection, with all wrappers removed.
+
+ If None is returned, no listener will be generated.
+
+ """
+ return None
class ExecutionContext(object):
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 7df858a64..ce24a9ae4 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -138,6 +138,20 @@ class DefaultDialect(base.Dialect):
self.do_rollback(connection.connection)
+ def on_connect(self):
+ """return a callable which sets up a newly created DBAPI connection.
+
+ This is used to set dialect-wide per-connection options such as isolation
+ modes, unicode modes, etc.
+
+ If a callable is returned, it will be assembled into a pool listener
+ that receives the direct DBAPI connection, with all wrappers removed.
+
+ If None is returned, no listener will be generated.
+
+ """
+ return None
+
def _check_unicode_returns(self, connection):
# Py2K
if self.supports_unicode_statements:
diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py
index 7c434105c..7fc39b91a 100644
--- a/lib/sqlalchemy/engine/strategies.py
+++ b/lib/sqlalchemy/engine/strategies.py
@@ -130,8 +130,16 @@ class DefaultEngineStrategy(EngineStrategy):
engine = engineclass(pool, dialect, u, **engine_args)
if _initialize:
- dialect.visit_pool(pool)
-
+ do_on_connect = dialect.on_connect()
+ if do_on_connect:
+ def on_connect(conn, rec):
+ conn = getattr(conn, '_sqla_unwrap', conn)
+ if conn is None:
+ return
+ do_on_connect(conn)
+
+ pool.add_listener({'first_connect': on_connect, 'connect':on_connect})
+
def first_connect(conn, rec):
c = base.Connection(engine, connection=conn)
dialect.initialize(c)
diff --git a/lib/sqlalchemy/test/engines.py b/lib/sqlalchemy/test/engines.py
index 58bfe2b3c..0cfd58d20 100644
--- a/lib/sqlalchemy/test/engines.py
+++ b/lib/sqlalchemy/test/engines.py
@@ -242,7 +242,11 @@ class ReplayableSession(object):
else:
buffer.append(result)
return result
-
+
+ @property
+ def _sqla_unwrap(self):
+ return self._subject
+
def __getattribute__(self, key):
try:
return object.__getattribute__(self, key)
@@ -275,7 +279,11 @@ class ReplayableSession(object):
return self
else:
return result
-
+
+ @property
+ def _sqla_unwrap(self):
+ return None
+
def __getattribute__(self, key):
try:
return object.__getattribute__(self, key)
@@ -290,10 +298,3 @@ class ReplayableSession(object):
else:
return result
-def unwrap_connection(conn):
- if conn.__class__.__name__ == 'Recorder':
- return conn._subject
- elif conn.__class__.__name__ == 'Player':
- return None
- else:
- return conn