From 57dc36a01b2b334a996f73f6a78b3bfbe4d9f2ec Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 29 Feb 2020 14:40:45 -0500 Subject: Ensure all nested exception throws have a cause Applied an explicit "cause" to most if not all internally raised exceptions that are raised from within an internal exception catch, to avoid misleading stacktraces that suggest an error within the handling of an exception. While it would be preferable to suppress the internally caught exception in the way that the ``__suppress_context__`` attribute would, there does not as yet seem to be a way to do this without suppressing an enclosing user constructed context, so for now it exposes the internally caught exception as the cause so that full information about the context of the error is maintained. Fixes: #4849 Change-Id: I55a86b29023675d9e5e49bc7edc5a2dc0bcd4751 --- lib/sqlalchemy/engine/base.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'lib/sqlalchemy/engine/base.py') diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index ce6c2e9c6..449f386ce 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -996,8 +996,10 @@ class Connection(Connectable): return self._execute_text(object_, multiparams, params) try: meth = object_._execute_on_connection - except AttributeError: - raise exc.ObjectNotExecutableError(object_) + except AttributeError as err: + util.raise_( + exc.ObjectNotExecutableError(object_), replace_context=err + ) else: return meth(self, multiparams, params) @@ -1400,7 +1402,7 @@ class Connection(Connectable): invalidate_pool_on_disconnect = not is_exit_exception if self._reentrant_error: - util.raise_from_cause( + util.raise_( exc.DBAPIError.instance( statement, parameters, @@ -1412,7 +1414,8 @@ class Connection(Connectable): if context is not None else None, ), - exc_info, + with_traceback=exc_info[2], + from_=e, ) self._reentrant_error = True try: @@ -1502,11 +1505,13 @@ class Connection(Connectable): self._autorollback() if newraise: - util.raise_from_cause(newraise, exc_info) + util.raise_(newraise, with_traceback=exc_info[2], from_=e) elif should_wrap: - util.raise_from_cause(sqlalchemy_exception, exc_info) + util.raise_( + sqlalchemy_exception, with_traceback=exc_info[2], from_=e + ) else: - util.reraise(*exc_info) + util.raise_(exc_info[1], with_traceback=exc_info[2]) finally: del self._reentrant_error @@ -1573,11 +1578,13 @@ class Connection(Connectable): ) = ctx.is_disconnect if newraise: - util.raise_from_cause(newraise, exc_info) + util.raise_(newraise, with_traceback=exc_info[2], from_=e) elif should_wrap: - util.raise_from_cause(sqlalchemy_exception, exc_info) + util.raise_( + sqlalchemy_exception, with_traceback=exc_info[2], from_=e + ) else: - util.reraise(*exc_info) + util.raise_(exc_info[1], with_traceback=exc_info[2]) def _run_ddl_visitor(self, visitorcallable, element, **kwargs): """run a DDL visitor. @@ -2329,7 +2336,9 @@ class Engine(Connectable, log.Identified): e, dialect, self ) else: - util.reraise(*sys.exc_info()) + util.raise_( + sys.exc_info()[1], with_traceback=sys.exc_info()[2] + ) def raw_connection(self, _connection=None): """Return a "raw" DBAPI connection from the connection pool. -- cgit v1.2.1