From: Mike Bayer Date: Sat, 24 Sep 2011 15:12:34 +0000 (-0400) Subject: - When an open Session is garbage collected, the objects X-Git-Tag: rel_0_7_3~26 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=212583b00795656633d34bffd4a5613fedadb5be;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - When an open Session is garbage collected, the objects within it which remain are considered detached again when they are add()-ed to a new Session. This is accomplished by an extra check that the previous "session_key" doesn't actually exist among the pool of Sessions. [ticket:2281] --- diff --git a/CHANGES b/CHANGES index 7b5b76089c..cc30f03c0d 100644 --- a/CHANGES +++ b/CHANGES @@ -89,6 +89,13 @@ CHANGES are constructed after existing ones have been used already. + - When an open Session is garbage collected, the objects + within it which remain are considered detached again + when they are add()-ed to a new Session. + This is accomplished by an extra check that the previous + "session_key" doesn't actually exist among the pool + of Sessions. [ticket:2281] + - New declarative features: - __declare_last__() method, establishes an event listener for the class method that will be called diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 3aa0d1de09..4044e83e35 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1473,7 +1473,9 @@ class Session(object): "present in this session." % (mapperutil.state_str(state), state.key)) - if state.session_id and state.session_id is not self.hash_key: + if state.session_id and \ + state.session_id is not self.hash_key and \ + state.session_id in _sessions: raise sa_exc.InvalidRequestError( "Object '%s' is already attached to session '%s' " "(this is '%s')" % (mapperutil.state_str(state), diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 282a8914dc..a723e7cfa5 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -1285,6 +1285,35 @@ class SessionTest(_fixtures.FixtureTest): del u3 gc_collect() + def test_auto_detach_on_gc_session(self): + users, User = self.tables.users, self.classes.User + + mapper(User, users) + + sess = Session() + + u1 = User(name='u1') + sess.add(u1) + sess.commit() + + # can't add u1 to Session, + # already belongs to u2 + s2 = Session() + assert_raises_message( + sa.exc.InvalidRequestError, + r".*is already attached to session", + s2.add, u1 + ) + + # garbage collect sess + del sess + gc_collect() + + # s2 lets it in now despite u1 having + # session_key + s2.add(u1) + assert u1 in s2 + class SessionDataTest(_fixtures.FixtureTest): def test_expunge_cascade(self): Address, addresses, users, User = (self.classes.Address,