From 8a1e619fb20df1be6ad2e0c563e451e17eb17628 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 28 Jan 2016 15:01:31 -0500 Subject: - revert the change first made in a6fe4dc, as we are now generalizing the warning here to all safe_reraise() cases in Python 2. - Revisiting :ticket:`2696`, first released in 1.0.10, which attempts to work around Python 2's lack of exception context reporting by emitting a warning for an exception that was interrupted by a second exception when attempting to roll back the already-failed transaction; this issue continues to occur for MySQL backends in conjunction with a savepoint that gets unexpectedly lost, which then causes a "no such savepoint" error when the rollback is attempted, obscuring what the original condition was. The approach has been generalized to the Core "safe reraise" function which takes place across the ORM and Core in any place that a transaction is being rolled back in response to an error which occurred trying to commit, including the context managers provided by :class:`.Session` and :class:`.Connection`, and taking place for operations such as a failure on "RELEASE SAVEPOINT". Previously, the fix was only in place for a specific path within the ORM flush/commit process; it now takes place for all transational context managers as well. fixes #2696 --- lib/sqlalchemy/orm/session.py | 16 ++-------------- lib/sqlalchemy/util/langhelpers.py | 7 +++++++ 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'lib/sqlalchemy') diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 56513860a..0af8f60fb 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -408,23 +408,11 @@ class SessionTransaction(object): for subtransaction in stx._iterate_parents(upto=self): subtransaction.close() - if _capture_exception: - captured_exception = sys.exc_info()[1] - boundary = self if self._state in (ACTIVE, PREPARED): for transaction in self._iterate_parents(): if transaction._parent is None or transaction.nested: - try: - transaction._rollback_impl() - except Exception: - if _capture_exception: - util.warn( - "An exception raised during a Session " - "persistence operation cannot be raised " - "due to an additional ROLLBACK exception; " - "the exception is: %s" % captured_exception) - raise + transaction._rollback_impl() transaction._state = DEACTIVE boundary = transaction break @@ -446,7 +434,7 @@ class SessionTransaction(object): self.close() if self._parent and _capture_exception: - self._parent._rollback_exception = captured_exception + self._parent._rollback_exception = sys.exc_info()[1] sess.dispatch.after_soft_rollback(sess, self) diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 11aa9384d..a1780536a 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -59,6 +59,13 @@ class safe_reraise(object): self._exc_info = None # remove potential circular references compat.reraise(exc_type, exc_value, exc_tb) else: + if not compat.py3k and self._exc_info and self._exc_info[1]: + # emulate Py3K's behavior of telling us when an exception + # occurs in an exception handler. + warn( + "An exception has occurred during handling of a " + "previous exception. The previous exception " + "is:\n %s %s\n" % (self._exc_info[0], self._exc_info[1])) self._exc_info = None # remove potential circular references compat.reraise(type_, value, traceback) -- cgit v1.2.1