]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug where internal assertion would fail in the case where
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 20 Feb 2015 05:01:19 +0000 (00:01 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 20 Feb 2015 05:01:19 +0000 (00:01 -0500)
an ``after_rollback()`` handler for a :class:`.Session` incorrectly
adds state to that :class:`.Session` within the handler, and the task
to warn and remove this state (established by :ticket:`2389`) attempts
to proceed.
fixes #3309

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/orm/session.py
test/orm/test_transaction.py

index 6836a15abd8aa778f31f2f8c4c62723d75990d67..0da20f66ea8853481b20d38217a5324ad6fedf4c 100644 (file)
 .. changelog::
     :version: 0.9.9
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3309
+
+        Fixed bug where internal assertion would fail in the case where
+        an ``after_rollback()`` handler for a :class:`.Session` incorrectly
+        adds state to that :class:`.Session` within the handler, and the task
+        to warn and remove this state (established by :ticket:`2389`) attempts
+        to proceed.
+
     .. change::
         :tags: bug, orm
         :pullreq: github:147
index c470269695bafd49cbdae98bf82647c8fc050829..a33b4261204a396b839cf78d85da5c0790d8fabf 100644 (file)
@@ -404,26 +404,29 @@ class SessionTransaction(object):
             for subtransaction in stx._iterate_parents(upto=self):
                 subtransaction.close()
 
+        boundary = self
         if self._state in (ACTIVE, PREPARED):
             for transaction in self._iterate_parents():
                 if transaction._parent is None or transaction.nested:
                     transaction._rollback_impl()
                     transaction._state = DEACTIVE
+                    boundary = transaction
                     break
                 else:
                     transaction._state = DEACTIVE
 
         sess = self.session
 
-        if self.session._enable_transaction_accounting and \
+        if sess._enable_transaction_accounting and \
                 not sess._is_clean():
+
             # if items were added, deleted, or mutated
             # here, we need to re-restore the snapshot
             util.warn(
                 "Session's state has been changed on "
                 "a non-active transaction - this state "
                 "will be discarded.")
-            self._restore_snapshot(dirty_only=self.nested)
+            boundary._restore_snapshot(dirty_only=boundary.nested)
 
         self.close()
         if self._parent and _capture_exception:
index 538a832a5fb91f433ab5cf6b6140a2bb781343bd..6bea5cc7b7b26ecf8c46ee639d4d71367678c957 100644 (file)
@@ -571,6 +571,35 @@ class SessionTransactionTest(FixtureTest):
         assert u1 in sess
         assert u1 not in sess.deleted
 
+    def test_warning_on_using_inactive_session_rollback_evt(self):
+        users, User = self.tables.users, self.classes.User
+
+        mapper(User, users)
+        sess = Session()
+        u1 = User(id=1, name='u1')
+        sess.add(u1)
+        sess.commit()
+
+        u3 = User(name='u3')
+
+        @event.listens_for(sess, "after_rollback")
+        def evt(s):
+            sess.add(u3)
+
+        sess.add(User(id=1, name='u2'))
+
+        def go():
+            assert_raises(
+                orm_exc.FlushError, sess.flush
+            )
+
+        assert_warnings(go,
+                        ["Session's state has been changed on a "
+                         "non-active transaction - this state "
+                         "will be discarded."],
+                        )
+        assert u3 not in sess
+
     def test_preserve_flush_error(self):
         User = self.classes.User