"""a plugin that emulates 0.1 Session behavior."""
import sqlalchemy.orm.objectstore as objectstore
import sqlalchemy.orm.unitofwork as unitofwork
import sqlalchemy.util as util
import sqlalchemy
import sqlalchemy.mods.threadlocal
class LegacySession(objectstore.Session):
def __init__(self, nest_on=None, hash_key=None, **kwargs):
super(LegacySession, self).__init__(**kwargs)
self.parent_uow = None
self.begin_count = 0
self.nest_on = util.to_list(nest_on)
self.__pushed_count = 0
def was_pushed(self):
if self.nest_on is None:
return
self.__pushed_count += 1
if self.__pushed_count == 1:
for n in self.nest_on:
n.push_session()
def was_popped(self):
if self.nest_on is None or self.__pushed_count == 0:
return
self.__pushed_count -= 1
if self.__pushed_count == 0:
for n in self.nest_on:
n.pop_session()
class SessionTrans(object):
"""returned by Session.begin(), denotes a transactionalized UnitOfWork instance.
call commit() on this to commit the transaction."""
def __init__(self, parent, uow, isactive):
self.__parent = parent
self.__isactive = isactive
self.__uow = uow
isactive = property(lambda s:s.__isactive, doc="True if this SessionTrans is the 'active' transaction marker, else its a no-op.")
parent = property(lambda s:s.__parent, doc="returns the parent Session of this SessionTrans object.")
uow = property(lambda s:s.__uow, doc="returns the parent UnitOfWork corresponding to this transaction.")
def begin(self):
"""calls begin() on the underlying Session object, returning a new no-op SessionTrans object."""
if self.parent.uow is not self.uow:
raise InvalidRequestError("This SessionTrans is no longer valid")
return self.parent.begin()
def commit(self):
"""commits the transaction noted by this SessionTrans object."""
self.__parent._trans_commit(self)
self.__isactive = False
def rollback(self):
"""rolls back the current UnitOfWork transaction, in the case that begin()
has been called. The changes logged since the begin() call are discarded."""
self.__parent._trans_rollback(self)
self.__isactive = False
def begin(self):
"""begins a new UnitOfWork transaction and returns a tranasaction-holding
object. commit() or rollback() should be called on the returned object.
commit() on the Session will do nothing while a transaction is pending, and further
calls to begin() will return no-op transactional objects."""
if self.parent_uow is not None:
return LegacySession.SessionTrans(self, self.uow, False)
self.parent_uow = self.uow
self.uow = unitofwork.UnitOfWork(identity_map = self.uow.identity_map)
return LegacySession.SessionTrans(self, self.uow, True)
def commit(self, *objects):
"""commits the current UnitOfWork transaction. called with
no arguments, this is only used
for "implicit" transactions when there was no begin().
if individual objects are submitted, then only those objects are committed, and the
begin/commit cycle is not affected."""
# if an object list is given, commit just those but dont
# change begin/commit status
if len(objects):
self._commit_uow(*objects)
self.uow.flush(self, *objects)
return
if self.parent_uow is None:
self._commit_uow()
def _trans_commit(self, trans):
if trans.uow is self.uow and trans.isactive:
try:
self._commit_uow()
finally:
self.uow = self.parent_uow
self.parent_uow = None
def _trans_rollback(self, trans):
if trans.uow is self.uow:
self.uow = self.parent_uow
self.parent_uow = None
def _commit_uow(self, *obj):
self.was_pushed()
try:
self.uow.flush(self, *obj)
finally:
self.was_popped()
def begin():
"""deprecated. use s = Session(new_imap=False)."""
return objectstore.get_session().begin()
def commit(*obj):
"""deprecated; use flush(*obj)"""
objectstore.get_session().flush(*obj)
def uow():
return objectstore.get_session()
def push_session(sess):
old = get_session()
if getattr(sess, '_previous', None) is not None:
raise InvalidRequestError("Given Session is already pushed onto some thread's stack")
sess._previous = old
session_registry.set(sess)
sess.was_pushed()
def pop_session():
sess = get_session()
old = sess._previous
sess._previous = None
session_registry.set(old)
sess.was_popped()
return old
def using_session(sess, func):
push_session(sess)
try:
return func()
finally:
pop_session()
def install_plugin():
objectstore.Session = LegacySession
objectstore.session_registry = util.ScopedRegistry(objectstore.Session)
objectstore.begin = begin
objectstore.commit = commit
objectstore.uow = uow
objectstore.push_session = push_session
objectstore.pop_session = pop_session
objectstore.using_session = using_session
install_plugin()
|