sessiontransaction contextmanager is broken due to new states in _assert_active()

Issue #2718 resolved
Michael Bayer
repo owner created an issue
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)

e = create_engine("postgresql://scott:tiger@localhost/test")

Base.metadata.drop_all(e)
Base.metadata.create_all(e)

s = Session(e)

s.add(A(id=1))
s.commit()

try:
    with s.begin_nested():
        s.add(A(id=1))
        s.flush()
except Exception, e:
    print e

with s.begin_nested():
    s.add(A(id=2))
    s.flush()

assert s.query(A).count() == 2

patch:

diff -r 62eeb1bf26c9599f8a3c8eeeeedfbb40072bd9d8 lib/sqlalchemy/orm/session.py
--- a/lib/sqlalchemy/orm/session.py Tue Apr 30 00:15:36 2013 -0400
+++ b/lib/sqlalchemy/orm/session.py Tue Apr 30 09:48:35 2013 -0400
@@ -169,6 +169,7 @@

     def _assert_active(self, prepared_ok=False,
                         rollback_ok=False,
+                        deactive_ok=False,
                         closed_msg="This transaction is closed"):
         if self._state is COMMITTED:
             raise sa_exc.InvalidRequestError(
@@ -182,7 +183,7 @@
                         "SQL can be emitted within this transaction."
                     )
         elif self._state is DEACTIVE:
-            if not rollback_ok:
+            if not deactive_ok and not rollback_ok:
                 if self._rollback_exception:
                     raise sa_exc.InvalidRequestError(
                         "This Session's transaction has been rolled back "
@@ -192,7 +193,7 @@
                         " Original exception was: %s"
                         % self._rollback_exception
                     )
-                else:
+                elif not deactive_ok:
                     raise sa_exc.InvalidRequestError(
                         "This Session's transaction has been rolled back "
                         "by a nested rollback() call.  To begin a new "
@@ -435,7 +436,7 @@
         return self

     def __exit__(self, type, value, traceback):
-        self._assert_active(prepared_ok=True)
+        self._assert_active(deactive_ok=True, prepared_ok=True)
         if self.session.transaction is None:
             return
         if type is None:

Comments (2)

  1. Log in to comment