From: Mike Bayer Date: Fri, 5 Dec 2014 21:34:43 +0000 (-0500) Subject: - move inner calls to _revalidate_connection() outside of existing X-Git-Tag: rel_1_0_0b1~189^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0639c199a547343d62134d2f233225fd2862ec45;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - move inner calls to _revalidate_connection() outside of existing _handle_dbapi_error(); these are now handled already and the reentrant call is not needed / breaks things. Adjustment to 41e7253dee168b8c26c49 / --- diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 901ab07eb3..235e1bf438 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -814,11 +814,11 @@ class Connection(Connectable): fn(self, default, multiparams, params) try: - try: - conn = self.__connection - except AttributeError: - conn = self._revalidate_connection() + conn = self.__connection + except AttributeError: + conn = self._revalidate_connection() + try: dialect = self.dialect ctx = dialect.execution_ctx_cls._init_default( dialect, self, conn) @@ -952,11 +952,11 @@ class Connection(Connectable): a :class:`.ResultProxy`.""" try: - try: - conn = self.__connection - except AttributeError: - conn = self._revalidate_connection() + conn = self.__connection + except AttributeError: + conn = self._revalidate_connection() + try: context = constructor(dialect, self, conn, *args) except Exception as e: self._handle_dbapi_exception(e, @@ -1246,6 +1246,7 @@ class Connection(Connectable): @classmethod def _handle_dbapi_exception_noconnection( cls, e, dialect, engine, connection): + exc_info = sys.exc_info() is_disconnect = dialect.is_disconnect(e, None, None) diff --git a/test/engine/test_parseconnect.py b/test/engine/test_parseconnect.py index 72a089acaa..b6d08cebaa 100644 --- a/test/engine/test_parseconnect.py +++ b/test/engine/test_parseconnect.py @@ -7,6 +7,7 @@ from sqlalchemy.testing import fixtures from sqlalchemy import testing from sqlalchemy.testing.mock import Mock, MagicMock from sqlalchemy import event +from sqlalchemy import select dialect = None @@ -279,7 +280,7 @@ class CreateEngineTest(fixtures.TestBase): ) @testing.requires.sqlite - def test_handle_error_event_reconnect(self): + def test_handle_error_event_revalidate(self): e = create_engine('sqlite://') dbapi = MockDBAPI() sqlite3 = e.dialect.dbapi @@ -295,6 +296,7 @@ class CreateEngineTest(fixtures.TestBase): def handle_error(ctx): assert ctx.engine is eng assert ctx.connection is conn + assert isinstance(ctx.sqlalchemy_exception, exc.ProgrammingError) raise MySpecialException("failed operation") conn = eng.connect() @@ -308,6 +310,37 @@ class CreateEngineTest(fixtures.TestBase): conn._revalidate_connection ) + @testing.requires.sqlite + def test_handle_error_event_implicit_revalidate(self): + e = create_engine('sqlite://') + dbapi = MockDBAPI() + sqlite3 = e.dialect.dbapi + dbapi.Error = sqlite3.Error, + dbapi.ProgrammingError = sqlite3.ProgrammingError + + class MySpecialException(Exception): + pass + + eng = create_engine('sqlite://', module=dbapi, _initialize=False) + + @event.listens_for(eng, "handle_error") + def handle_error(ctx): + assert ctx.engine is eng + assert ctx.connection is conn + assert isinstance(ctx.sqlalchemy_exception, exc.ProgrammingError) + raise MySpecialException("failed operation") + + conn = eng.connect() + conn.invalidate() + + dbapi.connect = Mock( + side_effect=sqlite3.ProgrammingError("random error")) + + assert_raises( + MySpecialException, + conn.execute, select([1]) + ) + @testing.requires.sqlite def test_handle_error_custom_connect(self): e = create_engine('sqlite://')