Add missing items to collection.__getstate__

the refactor in b606e47ddc / ticket:3457 failed
to adjust __getstate__ / __setstate__.  need to memoize
a few more things including the class itself so that we
can navigate back to "attr".

Change-Id: I4ece2a616cb8b9dac7b50763ca59e47d0f26cfdf
Fixes: #3852
This commit is contained in:
Mike Bayer
2016-11-14 16:09:13 -05:00
parent 88ca587eae
commit 3e063525f3
3 changed files with 47 additions and 1 deletions
+9
View File
@@ -29,6 +29,15 @@
autoincrement setting (see :ref:`change_3216`) would fail to emit
correctly when invoked upon a lower-case :func:`.table` construct.
.. change:: 3852
:tags: bug, orm
:tickets: 3852
Fixed regression in collections due to :ticket:`3457` whereby
deserialize during pickle or deepcopy would fail to establish all
attributes of an ORM collection, causing further mutation operations to
fail.
.. change:: default_schema
:tags: bug, engine
+7 -1
View File
@@ -714,12 +714,18 @@ class CollectionAdapter(object):
def __getstate__(self):
return {'key': self._key,
'owner_state': self.owner_state,
'data': self.data}
'owner_cls': self.owner_state.class_,
'data': self.data,
'invalidated': self.invalidated}
def __setstate__(self, d):
self._key = d['key']
self.owner_state = d['owner_state']
self._data = weakref.ref(d['data'])
self._converter = d['data']._sa_converter
d['data']._sa_adapter = self
self.invalidated = d['invalidated']
self.attr = getattr(d['owner_cls'], self._key).impl
def bulk_replace(values, existing_adapter, new_adapter):
+31
View File
@@ -1,6 +1,7 @@
from sqlalchemy.testing import eq_
from sqlalchemy.util import pickle
import sqlalchemy as sa
import copy
from sqlalchemy import testing
from sqlalchemy.testing.util import picklers
from sqlalchemy.testing import assert_raises_message
@@ -173,6 +174,36 @@ class PickleTest(fixtures.MappedTest):
sess.add(u2)
assert u2.addresses
def test_invalidated_flag_pickle(self):
users, addresses = (self.tables.users,
self.tables.addresses)
mapper(User, users, properties={
'addresses': relationship(Address, lazy='noload')
})
mapper(Address, addresses)
u1 = User()
u1.addresses.append(Address())
u2 = pickle.loads(pickle.dumps(u1))
u2.addresses.append(Address())
eq_(len(u2.addresses), 2)
def test_invalidated_flag_deepcopy(self):
users, addresses = (self.tables.users,
self.tables.addresses)
mapper(User, users, properties={
'addresses': relationship(Address, lazy='noload')
})
mapper(Address, addresses)
u1 = User()
u1.addresses.append(Address())
u2 = copy.deepcopy(u1)
u2.addresses.append(Address())
eq_(len(u2.addresses), 2)
@testing.requires.non_broken_pickle
def test_instance_deferred_cols(self):
users, addresses = (self.tables.users,