From 38bc8098419d7b1d4ddb975d85268515f52a3969 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 19 Oct 2014 16:53:45 -0400 Subject: - Fixed bug where :meth:`.Session.expunge` would not fully detach the given object if the object had been subject to a delete operation that was flushed, but not committed. This would also affect related operations like :func:`.make_transient`. fixes #3139 --- lib/sqlalchemy/orm/session.py | 12 ++++++++---- lib/sqlalchemy/orm/state.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index db9d3a51d..f23983cbc 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -292,7 +292,7 @@ class SessionTransaction(object): for s in self.session.identity_map.all_states(): s._expire(s.dict, self.session.identity_map._modified) for s in self._deleted: - s.session_id = None + s._detach() self._deleted.clear() elif self.nested: self._parent._new.update(self._new) @@ -1409,6 +1409,7 @@ class Session(_SessionClassMethods): state._detach() elif self.transaction: self.transaction._deleted.pop(state, None) + state._detach() def _register_newly_persistent(self, states): for state in states: @@ -2449,16 +2450,19 @@ def make_transient_to_detached(instance): def object_session(instance): - """Return the ``Session`` to which instance belongs. + """Return the :class:`.Session` to which the given instance belongs. - If the instance is not a mapped instance, an error is raised. + This is essentially the same as the :attr:`.InstanceState.session` + accessor. See that attribute for details. """ try: - return _state_session(attributes.instance_state(instance)) + state = attributes.instance_state(instance) except exc.NO_STATE: raise exc.UnmappedInstanceError(instance) + else: + return _state_session(state) _new_sessionid = util.counter() diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 4756f1707..560149de5 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -145,7 +145,16 @@ class InstanceState(interfaces.InspectionAttr): @util.dependencies("sqlalchemy.orm.session") def session(self, sessionlib): """Return the owning :class:`.Session` for this instance, - or ``None`` if none available.""" + or ``None`` if none available. + + Note that the result here can in some cases be *different* + from that of ``obj in session``; an object that's been deleted + will report as not ``in session``, however if the transaction is + still in progress, this attribute will still refer to that session. + Only when the transaction is completed does the object become + fully detached under normal circumstances. + + """ return sessionlib._state_session(self) @property -- cgit v1.2.1