[Sqlalchemy-commits] [5881] sqlalchemy/branches/rel_0_6: - Added support for create_engine( isolati
Brought to you by:
zzzeek
From: <co...@sq...> - 2009-03-31 19:49:23
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[5881] sqlalchemy/branches/rel_0_6: - Added support for create_engine( isolation_level=...); postgres &</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>5881</dd> <dt>Author</dt> <dd>jek</dd> <dt>Date</dt> <dd>2009-03-31 15:49:13 -0400 (Tue, 31 Mar 2009)</dd> </dl> <h3>Log Message</h3> <pre>- Added support for create_engine(isolation_level=...); postgres & sqlite initially [ticket:443] - Dialects gained visit_pool - Pools gained a first_connect event Patch from Adam Lowry. Thank you Adam!</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesrel_0_606CHANGES">sqlalchemy/branches/rel_0_6/06CHANGES</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemydialectspostgresbasepy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/base.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemydialectspostgrespsycopg2py">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/psycopg2.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemyenginebasepy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/base.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemyenginedefaultpy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/default.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemyenginestrategiespy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/strategies.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemyinterfacespy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/interfaces.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6libsqlalchemypoolpy">sqlalchemy/branches/rel_0_6/lib/sqlalchemy/pool.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6testdialectpostgrespy">sqlalchemy/branches/rel_0_6/test/dialect/postgres.py</a></li> <li><a href="#sqlalchemybranchesrel_0_6testenginepoolpy">sqlalchemy/branches/rel_0_6/test/engine/pool.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesrel_0_606CHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/06CHANGES (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/06CHANGES 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/06CHANGES 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -7,11 +7,18 @@ </span><span class="cx"> There is no implicit fallback onto "fetch". Failure of evaluation is based </span><span class="cx"> on the structure of criteria, so success/failure is deterministic based on </span><span class="cx"> code structure. </span><del>- </del><ins>+ +- engines + - transaction isolation level may be specified with + create_engine(... isolation_level="..."); available on + postgresql and sqlite. [ticket:443] + </ins><span class="cx"> - dialect refactor </span><span class="cx"> - server_version_info becomes a static attribute. </span><del>- - create_engine() now establishes an initial connection immediately upon - creation, which is passed to the dialect to determine connection properties. </del><ins>+ - dialects receive an initialize() event on initial connection to + determine connection properties. + - dialects receive a visit_pool event have an opportunity to + establish pool listeners. </ins><span class="cx"> - cached TypeEngine classes are cached per-dialect class instead of per-dialect. </span><span class="cx"> </span><span class="cx"> - mysql </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemydialectspostgresbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/base.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/base.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/base.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -445,8 +445,26 @@ </span><span class="cx"> preparer = PGIdentifierPreparer </span><span class="cx"> defaultrunner = PGDefaultRunner </span><span class="cx"> inspector = PGInspector </span><ins>+ isolation_level = None </ins><span class="cx"> </span><ins>+ def __init__(self, isolation_level=None, **kwargs): + default.DefaultDialect.__init__(self, **kwargs) + self.isolation_level = isolation_level </ins><span class="cx"> </span><ins>+ 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)) + </ins><span class="cx"> def do_begin_twophase(self, connection, xid): </span><span class="cx"> self.do_begin(connection.connection) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemydialectspostgrespsycopg2py"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/psycopg2.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/psycopg2.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/dialects/postgres/psycopg2.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -24,6 +24,10 @@ </span><span class="cx"> uses special row-buffering behavior when this feature is enabled, such that groups of 100 rows </span><span class="cx"> at a time are fetched over the wire to reduce conversational overhead. </span><span class="cx"> </span><ins>+* *isolation_level* - Sets the transaction isolation level for each transaction + within the engine. Valid isolation levels are `READ_COMMITTED`, + `READ_UNCOMMITTED`, `REPEATABLE_READ`, and `SERIALIZABLE`. + </ins><span class="cx"> Transactions </span><span class="cx"> ------------ </span><span class="cx"> </span><span class="lines">@@ -116,7 +120,6 @@ </span><span class="cx"> } </span><span class="cx"> ) </span><span class="cx"> </span><del>- </del><span class="cx"> def __init__(self, server_side_cursors=False, **kwargs): </span><span class="cx"> PGDialect.__init__(self, **kwargs) </span><span class="cx"> self.server_side_cursors = server_side_cursors </span><span class="lines">@@ -145,4 +148,4 @@ </span><span class="cx"> return False </span><span class="cx"> </span><span class="cx"> dialect = Postgres_psycopg2 </span><del>- </del><span class="cx">\ No newline at end of file </span><ins>+ </ins></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemyenginebasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/base.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/base.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/base.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -390,7 +390,10 @@ </span><span class="cx"> </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><ins>+ def visit_pool(self, pool): + """Executed after a pool is created.""" </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> class ExecutionContext(object): </span><span class="cx"> """A messenger object for a Dialect that corresponds to a single execution. </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemyenginedefaultpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/default.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/default.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/default.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -102,7 +102,10 @@ </span><span class="cx"> def validate_identifier(self, ident): </span><span class="cx"> if len(ident) > self.max_identifier_length: </span><span class="cx"> raise exc.IdentifierError("Identifier '%s' exceeds maximum length of %d characters" % (ident, self.max_identifier_length)) </span><del>- </del><ins>+ + def connect(self, *cargs, **cparams): + return self.dbapi.connect(*cargs, **cparams) + </ins><span class="cx"> def do_begin(self, connection): </span><span class="cx"> """Implementations might want to put logic here for turning </span><span class="cx"> autocommit on/off, etc. </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemyenginestrategiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/strategies.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/strategies.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/engine/strategies.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -13,7 +13,6 @@ </span><span class="cx"> from sqlalchemy.engine import base, threadlocal, url </span><span class="cx"> from sqlalchemy import util, exc </span><span class="cx"> from sqlalchemy import pool as poollib </span><del>-from sqlalchemy import interfaces </del><span class="cx"> </span><span class="cx"> strategies = {} </span><span class="cx"> </span><span class="lines">@@ -75,7 +74,7 @@ </span><span class="cx"> if pool is None: </span><span class="cx"> def connect(): </span><span class="cx"> try: </span><del>- return dbapi.connect(*cargs, **cparams) </del><ins>+ return dialect.connect(*cargs, **cparams) </ins><span class="cx"> except Exception, e: </span><span class="cx"> import sys </span><span class="cx"> raise exc.DBAPIError.instance(None, None, e), None, sys.exc_info()[2] </span><span class="lines">@@ -126,13 +125,14 @@ </span><span class="cx"> engine = engineclass(pool, dialect, u, **engine_args) </span><span class="cx"> </span><span class="cx"> if _initialize: </span><del>- class OnInit(interfaces.PoolListener): - def connect(self, conn, rec): </del><ins>+ class OnInit(object): + def first_connect(self, conn, rec): </ins><span class="cx"> c = base.Connection(engine, connection=conn) </span><span class="cx"> dialect.initialize(c) </span><del>- pool._on_connect.remove(self) - pool._on_connect.insert(0, OnInit()) - </del><ins>+ pool._on_first_connect.insert(0, OnInit()) + + dialect.visit_pool(pool) + </ins><span class="cx"> return engine </span><span class="cx"> </span><span class="cx"> def pool_threadlocal(self): </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemyinterfacespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/interfaces.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/interfaces.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/interfaces.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -71,6 +71,18 @@ </span><span class="cx"> </span><span class="cx"> """ </span><span class="cx"> </span><ins>+ def first_connect(self, dbapi_con, con_record): + """Called exactly once for the first DB-API connection. + + dbapi_con + A newly connected raw DB-API connection (not a SQLAlchemy + ``Connection`` wrapper). + + con_record + The ``_ConnectionRecord`` that persistently manages the connection + + """ + </ins><span class="cx"> def checkout(self, dbapi_con, con_record, con_proxy): </span><span class="cx"> """Called when a connection is retrieved from the Pool. </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6libsqlalchemypoolpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/lib/sqlalchemy/pool.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/lib/sqlalchemy/pool.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/lib/sqlalchemy/pool.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -108,6 +108,7 @@ </span><span class="cx"> self.echo = echo </span><span class="cx"> self.listeners = [] </span><span class="cx"> self._on_connect = [] </span><ins>+ self._on_first_connect = [] </ins><span class="cx"> self._on_checkout = [] </span><span class="cx"> self._on_checkin = [] </span><span class="cx"> </span><span class="lines">@@ -178,12 +179,14 @@ </span><span class="cx"> </span><span class="cx"> """ </span><span class="cx"> </span><del>- listener = as_interface( - listener, methods=('connect', 'checkout', 'checkin')) </del><ins>+ listener = as_interface(listener, + methods=('connect', 'first_connect', 'checkout', 'checkin')) </ins><span class="cx"> </span><span class="cx"> self.listeners.append(listener) </span><span class="cx"> if hasattr(listener, 'connect'): </span><span class="cx"> self._on_connect.append(listener) </span><ins>+ if hasattr(listener, 'first_connect'): + self._on_first_connect.append(listener) </ins><span class="cx"> if hasattr(listener, 'checkout'): </span><span class="cx"> self._on_checkout.append(listener) </span><span class="cx"> if hasattr(listener, 'checkin'): </span><span class="lines">@@ -197,6 +200,10 @@ </span><span class="cx"> self.__pool = pool </span><span class="cx"> self.connection = self.__connect() </span><span class="cx"> self.info = {} </span><ins>+ ls = pool.__dict__.pop('_on_first_connect', None) + if ls is not None: + for l in ls: + l.first_connect(self.connection, self) </ins><span class="cx"> if pool._on_connect: </span><span class="cx"> for l in pool._on_connect: </span><span class="cx"> l.connect(self.connection, self) </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6testdialectpostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/test/dialect/postgres.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/test/dialect/postgres.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/test/dialect/postgres.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -708,7 +708,21 @@ </span><span class="cx"> warnings.warn = capture_warnings._orig_showwarning </span><span class="cx"> m1.drop_all() </span><span class="cx"> </span><ins>+ def test_set_isolation_level(self): + """Test setting the isolation level with create_engine""" + eng = create_engine(testing.db.url) + self.assertEquals( + eng.execute("show transaction isolation level").scalar(), + 'read committed') + eng = create_engine(testing.db.url, isolation_level="SERIALIZABLE") + self.assertEquals( + eng.execute("show transaction isolation level").scalar(), + 'serializable') + eng = create_engine(testing.db.url, isolation_level="FOO") + self.assertRaises(eng.dialect.dbapi.ProgrammingError, eng.execute, + "show transaction isolation level") </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> class TimezoneTest(TestBase, AssertsExecutionResults): </span><span class="cx"> """Test timezone-aware datetimes. </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesrel_0_6testenginepoolpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/rel_0_6/test/engine/pool.py (5880 => 5881)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/rel_0_6/test/engine/pool.py 2009-03-31 19:29:27 UTC (rev 5880) +++ sqlalchemy/branches/rel_0_6/test/engine/pool.py 2009-03-31 19:49:13 UTC (rev 5881) </span><span class="lines">@@ -1,8 +1,8 @@ </span><span class="cx"> import testenv; testenv.configure_for_tests() </span><span class="cx"> import threading, time, gc </span><del>-from sqlalchemy import pool, interfaces </del><ins>+from sqlalchemy import pool, interfaces, create_engine </ins><span class="cx"> import testlib.sa as tsa </span><del>-from testlib import TestBase </del><ins>+from testlib import TestBase, testing </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> mcid = 1 </span><span class="lines">@@ -164,6 +164,8 @@ </span><span class="cx"> def __init__(self): </span><span class="cx"> if hasattr(self, 'connect'): </span><span class="cx"> self.connect = self.inst_connect </span><ins>+ if hasattr(self, 'first_connect'): + self.first_connect = self.inst_first_connect </ins><span class="cx"> if hasattr(self, 'checkout'): </span><span class="cx"> self.checkout = self.inst_checkout </span><span class="cx"> if hasattr(self, 'checkin'): </span><span class="lines">@@ -171,14 +173,17 @@ </span><span class="cx"> self.clear() </span><span class="cx"> def clear(self): </span><span class="cx"> self.connected = [] </span><ins>+ self.first_connected = [] </ins><span class="cx"> self.checked_out = [] </span><span class="cx"> self.checked_in = [] </span><del>- def assert_total(innerself, conn, cout, cin): </del><ins>+ def assert_total(innerself, conn, fconn, cout, cin): </ins><span class="cx"> self.assert_(len(innerself.connected) == conn) </span><ins>+ self.assert_(len(innerself.first_connected) == fconn) </ins><span class="cx"> self.assert_(len(innerself.checked_out) == cout) </span><span class="cx"> self.assert_(len(innerself.checked_in) == cin) </span><del>- def assert_in(innerself, item, in_conn, in_cout, in_cin): </del><ins>+ def assert_in(innerself, item, in_conn, in_fconn, in_cout, in_cin): </ins><span class="cx"> self.assert_((item in innerself.connected) == in_conn) </span><ins>+ self.assert_((item in innerself.first_connected) == in_fconn) </ins><span class="cx"> self.assert_((item in innerself.checked_out) == in_cout) </span><span class="cx"> self.assert_((item in innerself.checked_in) == in_cin) </span><span class="cx"> def inst_connect(self, con, record): </span><span class="lines">@@ -186,6 +191,11 @@ </span><span class="cx"> assert con is not None </span><span class="cx"> assert record is not None </span><span class="cx"> self.connected.append(con) </span><ins>+ def inst_first_connect(self, con, record): + print "first_connect(%s, %s)" % (con, record) + assert con is not None + assert record is not None + self.first_connected.append(con) </ins><span class="cx"> def inst_checkout(self, con, record, proxy): </span><span class="cx"> print "checkout(%s, %s, %s)" % (con, record, proxy) </span><span class="cx"> assert con is not None </span><span class="lines">@@ -203,6 +213,9 @@ </span><span class="cx"> class ListenConnect(InstrumentingListener): </span><span class="cx"> def connect(self, con, record): </span><span class="cx"> pass </span><ins>+ class ListenFirstConnect(InstrumentingListener): + def first_connect(self, con, record): + pass </ins><span class="cx"> class ListenCheckOut(InstrumentingListener): </span><span class="cx"> def checkout(self, con, record, proxy, num): </span><span class="cx"> pass </span><span class="lines">@@ -214,40 +227,44 @@ </span><span class="cx"> return pool.QueuePool(creator=lambda: dbapi.connect('foo.db'), </span><span class="cx"> use_threadlocal=False, **kw) </span><span class="cx"> </span><del>- def assert_listeners(p, total, conn, cout, cin): </del><ins>+ def assert_listeners(p, total, conn, fconn, cout, cin): </ins><span class="cx"> for instance in (p, p.recreate()): </span><span class="cx"> self.assert_(len(instance.listeners) == total) </span><span class="cx"> self.assert_(len(instance._on_connect) == conn) </span><ins>+ self.assert_(len(instance._on_first_connect) == fconn) </ins><span class="cx"> self.assert_(len(instance._on_checkout) == cout) </span><span class="cx"> self.assert_(len(instance._on_checkin) == cin) </span><span class="cx"> </span><span class="cx"> p = _pool() </span><del>- assert_listeners(p, 0, 0, 0, 0) </del><ins>+ assert_listeners(p, 0, 0, 0, 0, 0) </ins><span class="cx"> </span><span class="cx"> p.add_listener(ListenAll()) </span><del>- assert_listeners(p, 1, 1, 1, 1) </del><ins>+ assert_listeners(p, 1, 1, 1, 1, 1) </ins><span class="cx"> </span><span class="cx"> p.add_listener(ListenConnect()) </span><del>- assert_listeners(p, 2, 2, 1, 1) </del><ins>+ assert_listeners(p, 2, 2, 1, 1, 1) </ins><span class="cx"> </span><ins>+ p.add_listener(ListenFirstConnect()) + assert_listeners(p, 3, 2, 2, 1, 1) + </ins><span class="cx"> p.add_listener(ListenCheckOut()) </span><del>- assert_listeners(p, 3, 2, 2, 1) </del><ins>+ assert_listeners(p, 4, 2, 2, 2, 1) </ins><span class="cx"> </span><span class="cx"> p.add_listener(ListenCheckIn()) </span><del>- assert_listeners(p, 4, 2, 2, 2) </del><ins>+ assert_listeners(p, 5, 2, 2, 2, 2) </ins><span class="cx"> del p </span><span class="cx"> </span><span class="cx"> print "----" </span><span class="cx"> snoop = ListenAll() </span><span class="cx"> p = _pool(listeners=[snoop]) </span><del>- assert_listeners(p, 1, 1, 1, 1) </del><ins>+ assert_listeners(p, 1, 1, 1, 1, 1) </ins><span class="cx"> </span><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(1, 1, 0) </del><ins>+ snoop.assert_total(1, 1, 1, 0) </ins><span class="cx"> cc = c.connection </span><del>- snoop.assert_in(cc, True, True, False) </del><ins>+ snoop.assert_in(cc, True, True, True, False) </ins><span class="cx"> c.close() </span><del>- snoop.assert_in(cc, True, True, True) </del><ins>+ snoop.assert_in(cc, True, True, True, True) </ins><span class="cx"> del c, cc </span><span class="cx"> </span><span class="cx"> snoop.clear() </span><span class="lines">@@ -255,10 +272,10 @@ </span><span class="cx"> # this one depends on immediate gc </span><span class="cx"> c = p.connect() </span><span class="cx"> cc = c.connection </span><del>- snoop.assert_in(cc, False, True, False) - snoop.assert_total(0, 1, 0) </del><ins>+ snoop.assert_in(cc, False, False, True, False) + snoop.assert_total(0, 0, 1, 0) </ins><span class="cx"> del c, cc </span><del>- snoop.assert_total(0, 1, 1) </del><ins>+ snoop.assert_total(0, 0, 1, 1) </ins><span class="cx"> </span><span class="cx"> p.dispose() </span><span class="cx"> snoop.clear() </span><span class="lines">@@ -266,44 +283,44 @@ </span><span class="cx"> c = p.connect() </span><span class="cx"> c.close() </span><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(1, 2, 1) </del><ins>+ snoop.assert_total(1, 0, 2, 1) </ins><span class="cx"> c.close() </span><del>- snoop.assert_total(1, 2, 2) </del><ins>+ snoop.assert_total(1, 0, 2, 2) </ins><span class="cx"> </span><span class="cx"> # invalidation </span><span class="cx"> p.dispose() </span><span class="cx"> snoop.clear() </span><span class="cx"> </span><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(1, 1, 0) </del><ins>+ snoop.assert_total(1, 0, 1, 0) </ins><span class="cx"> c.invalidate() </span><del>- snoop.assert_total(1, 1, 1) </del><ins>+ snoop.assert_total(1, 0, 1, 1) </ins><span class="cx"> c.close() </span><del>- snoop.assert_total(1, 1, 1) </del><ins>+ snoop.assert_total(1, 0, 1, 1) </ins><span class="cx"> del c </span><del>- snoop.assert_total(1, 1, 1) </del><ins>+ snoop.assert_total(1, 0, 1, 1) </ins><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(2, 2, 1) </del><ins>+ snoop.assert_total(2, 0, 2, 1) </ins><span class="cx"> c.close() </span><span class="cx"> del c </span><del>- snoop.assert_total(2, 2, 2) </del><ins>+ snoop.assert_total(2, 0, 2, 2) </ins><span class="cx"> </span><span class="cx"> # detached </span><span class="cx"> p.dispose() </span><span class="cx"> snoop.clear() </span><span class="cx"> </span><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(1, 1, 0) </del><ins>+ snoop.assert_total(1, 0, 1, 0) </ins><span class="cx"> c.detach() </span><del>- snoop.assert_total(1, 1, 0) </del><ins>+ snoop.assert_total(1, 0, 1, 0) </ins><span class="cx"> c.close() </span><span class="cx"> del c </span><del>- snoop.assert_total(1, 1, 0) </del><ins>+ snoop.assert_total(1, 0, 1, 0) </ins><span class="cx"> c = p.connect() </span><del>- snoop.assert_total(2, 2, 0) </del><ins>+ snoop.assert_total(2, 0, 2, 0) </ins><span class="cx"> c.close() </span><span class="cx"> del c </span><del>- snoop.assert_total(2, 2, 1) </del><ins>+ snoop.assert_total(2, 0, 2, 1) </ins><span class="cx"> </span><span class="cx"> def test_listeners_callables(self): </span><span class="cx"> dbapi = MockDBAPI() </span><span class="lines">@@ -362,6 +379,18 @@ </span><span class="cx"> c.close() </span><span class="cx"> assert counts == [1, 2, 3] </span><span class="cx"> </span><ins>+ def test_listener_after_oninit(self): + """Test that listeners are called after OnInit is removed""" + called = [] + def listener(*args): + called.append(True) + listener.connect = listener + engine = create_engine(testing.db.url) + engine.pool.add_listener(listener) + engine.execute('select 1') + assert called, "Listener not called on connect" + + </ins><span class="cx"> class QueuePoolTest(PoolTestBase): </span><span class="cx"> </span><span class="cx"> def testqueuepool_del(self): </span></span></pre> </div> </div> </body> </html> |