From a66861031a85063c9de8874559815f7ee0bab998 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 24 Apr 2012 15:52:09 -0400 Subject: [PATCH] - [feature] The after_attach event is now emitted after the object is established in Session.new or Session.identity_map upon Session.add(), Session.merge(), etc., so that the object is represented in these collections when the event is called. [ticket:2464] --- CHANGES | 8 ++++++++ lib/sqlalchemy/orm/session.py | 4 ++-- test/orm/test_events.py | 21 ++++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 249b2db91f..38d51bc8ac 100644 --- a/CHANGES +++ b/CHANGES @@ -105,6 +105,14 @@ CHANGES "is_remove" when this flag is used. also in 0.7.7. + - [feature] The after_attach event is now + emitted after the object is established + in Session.new or Session.identity_map + upon Session.add(), Session.merge(), + etc., so that the object is represented + in these collections when the event + is called. [ticket:2464] + - [bug] Fixed bug whereby polymorphic_on column that's not otherwise mapped on the class would be incorrectly included diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index ab9de70eac..7c2cd8f0e1 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1460,10 +1460,10 @@ class Session(object): "Object '%s' already has an identity - it can't be registered " "as pending" % mapperutil.state_str(state)) - self._attach(state) if state not in self._new: self._new[state] = state.obj() state.insert_order = len(self._new) + self._attach(state) def _update_impl(self, state): if (self.identity_map.contains_state(state) and @@ -1481,9 +1481,9 @@ class Session(object): "function to send this object back to the transient state." % mapperutil.state_str(state) ) - self._attach(state) self._deleted.pop(state, None) self.identity_map.add(state) + self._attach(state) def _save_or_update_impl(self, state): if state.key is None: diff --git a/test/orm/test_events.py b/test/orm/test_events.py index f8158369c2..e5b597cdaf 100644 --- a/test/orm/test_events.py +++ b/test/orm/test_events.py @@ -6,7 +6,7 @@ from test.lib.schema import Table, Column from sqlalchemy.orm import mapper, relationship, \ create_session, class_mapper, \ Mapper, column_property, \ - Session, sessionmaker + Session, sessionmaker, attributes from sqlalchemy.orm.instrumentation import ClassManager from test.lib.testing import eq_ from test.lib import fixtures @@ -658,6 +658,25 @@ class SessionEventsTest(_RemoveListeners, _fixtures.FixtureTest): eq_(canary, ['before_commit', 'before_flush', 'after_flush', 'after_flush_postexec', 'after_commit']) + def test_state_after_attach(self): + User, users = self.classes.User, self.tables.users + sess = Session() + + @event.listens_for(sess, "after_attach") + def listener(session, inst): + state = attributes.instance_state(inst) + if state.key: + assert session.identity_map[state.key] is inst + else: + assert inst in session.new + + mapper(User, users) + u= User(name='u1') + sess.add(u) + sess.flush() + sess.expunge(u) + sess.add(u) + def test_standalone_on_commit_hook(self): sess, canary = self._listener_fixture() sess.commit() -- 2.47.3