diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-10-03 12:25:42 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2016-10-03 12:25:42 -0400 |
| commit | 728ce8cc480d0ada690e5a97067cff821b9a65f3 (patch) | |
| tree | c9e12ecd610b87c40d2ce1ba1cdd4b61d2d33a15 /lib/sqlalchemy/orm | |
| parent | 333414fe94941a6a58e7d8e45042548eb2d58119 (diff) | |
| download | sqlalchemy-728ce8cc480d0ada690e5a97067cff821b9a65f3.tar.gz | |
Ensure strong ref to obj before calling persistent_to_deleted, others
Add checks in spots where state.obj() might be late-GC'ed before
we get a chance to call the event. There may be more cases
of these which we should address as they come up. The Session
should always be maintaining strong refs to objects that have
pending operations left on them, so for these cases we need
to ensure that ref remains long enough for the event to be called.
Change-Id: I1a7c7bc57130acc11f54ad55924af2e36ac75101
Fixes: #3808
Diffstat (limited to 'lib/sqlalchemy/orm')
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/state.py | 16 |
2 files changed, 23 insertions, 5 deletions
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 4a65e0719..b492cbb7f 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -1642,6 +1642,11 @@ class Session(_SessionClassMethods): if self._enable_transaction_accounting and self.transaction: self.transaction._deleted[state] = True + if persistent_to_deleted is not None: + # get a strong reference before we pop out of + # self._deleted + obj = state.obj() + self.identity_map.safe_discard(state) self._deleted.pop(state, None) state._deleted = True @@ -1649,7 +1654,7 @@ class Session(_SessionClassMethods): # is still in the transaction snapshot and needs to be # tracked as part of that if persistent_to_deleted is not None: - persistent_to_deleted(self, state.obj()) + persistent_to_deleted(self, obj) def add(self, instance, _warn=True): """Place an object in the ``Session``. @@ -1964,6 +1969,11 @@ class Session(_SessionClassMethods): ) obj = state.obj() + + # check for late gc + if obj is None: + return + to_attach = self._before_attach(state, obj) self._deleted.pop(state, None) diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 2704367f9..519220e34 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -328,13 +328,21 @@ class InstanceState(interfaces.InspectionAttr): if persistent: if to_transient: if persistent_to_transient is not None: - persistent_to_transient(session, state.obj()) + obj = state.obj() + if obj is not None: + persistent_to_transient(session, obj) elif persistent_to_detached is not None: - persistent_to_detached(session, state.obj()) + obj = state.obj() + if obj is not None: + persistent_to_detached(session, obj) elif deleted and deleted_to_detached is not None: - deleted_to_detached(session, state.obj()) + obj = state.obj() + if obj is not None: + deleted_to_detached(session, obj) elif pending and pending_to_transient is not None: - pending_to_transient(session, state.obj()) + obj = state.obj() + if obj is not None: + pending_to_transient(session, obj) state._strong_obj = None |
