inside of the flush, but for now, results
can't be guaranteed.
+ - [bug] Continuing [ticket:2566] regarding extra
+ state post-flush due to event listeners;
+ any states that are marked as "dirty" from an
+ attribute perspective, usually via column-attribute
+ set events within after_insert(), after_update(),
+ etc., will get the "history" flag reset
+ in all cases, instead of only those instances
+ that were part of the flush. This has the effect
+ that this "dirty" state doesn't carry over
+ after the flush and won't result in UPDATE
+ statements. A warning is emitted to this
+ effect; the set_committed_state()
+ method can be used to assign attributes on objects
+ without producing history events. [ticket:2582]
+
- [feature] ORM entities can be passed
to select() as well as the select_from(),
correlate(), and correlate_except()
flush_context.finalize_flush_changes()
+ if not objects and self.identity_map._modified:
+ len_ = len(self.identity_map._modified)
+
+ statelib.InstanceState._commit_all_states(
+ [(state, state.dict) for state in
+ self.identity_map._modified],
+ instance_dict=self.identity_map)
+ util.warn("Attribute history events accumulated on %d "
+ "previously clean instances "
+ "within inner-flush event handlers have been reset, "
+ "and will not result in database updates. "
+ "Consider using set_committed_value() within "
+ "inner-flush event handlers to avoid this warning."
+ % len_)
+
# useful assertions:
#if not objects:
# assert not self.identity_map._modified
del u3
gc_collect()
+ def _test_extra_dirty_state(self):
+ users, User = self.tables.users, self.classes.User
+ m = mapper(User, users)
+
+ s = Session()
+
+ @event.listens_for(m, "after_update")
+ def e(mapper, conn, target):
+ sess = object_session(target)
+ for entry in sess.identity_map.values():
+ entry.name = "5"
+
+ a1, a2 = User(name="1"), User(name="2")
+
+ s.add_all([a1, a2])
+ s.commit()
+
+ a1.name = "3"
+ return s, a1, a2
+
+ def test_extra_dirty_state_post_flush_warning(self):
+ s, a1, a2 = self._test_extra_dirty_state()
+ assert_raises_message(
+ sa.exc.SAWarning,
+ "Attribute history events accumulated on 1 previously "
+ "clean instances",
+ s.commit
+ )
+
+ def test_extra_dirty_state_post_flush_state(self):
+ s, a1, a2 = self._test_extra_dirty_state()
+ canary = []
+ @event.listens_for(s, "after_flush_postexec")
+ def e(sess, ctx):
+ canary.append(bool(sess.identity_map._modified))
+
+ @testing.emits_warning("Attribute")
+ def go():
+ s.commit()
+ go()
+ eq_(canary, [False])
+
class SessionStateWFixtureTest(_fixtures.FixtureTest):
def test_autoflush_rollback(self):