- fixed __setstate__ method of CollectionAdapter to not

fail during deserialize where parent InstanceState not
yet unserialized.  [ticket:1802]
This commit is contained in:
Mike Bayer
2010-05-13 15:36:22 -04:00
parent 0a8f2207f0
commit e352e255a7
3 changed files with 60 additions and 8 deletions
+4
View File
@@ -12,6 +12,10 @@ CHANGES
- session.merge() will not expire attributes on the returned
instance if that instance is "pending". [ticket:1789]
- fixed __setstate__ method of CollectionAdapter to not
fail during deserialize where parent InstanceState not
yet unserialized. [ticket:1802]
- sql
- expr.in_() now accepts a text() construct as the argument.
Grouping parenthesis are added automatically, i.e. usage
+12 -7
View File
@@ -471,15 +471,20 @@ class CollectionAdapter(object):
"""
def __init__(self, attr, owner_state, data):
self.attr = attr
# TODO: figure out what this being a weakref buys us
self._key = attr.key
self._data = weakref.ref(data)
self.owner_state = owner_state
self.link_to_self(data)
@property
def data(self):
"The entity collection being adapted."
return self._data()
data = property(lambda s: s._data(),
doc="The entity collection being adapted.")
@util.memoized_property
def attr(self):
return self.owner_state.manager[self._key].impl
def link_to_self(self, data):
"""Link a collection to this adapter, and fire a link event."""
setattr(data, '_sa_adapter', self)
@@ -619,12 +624,12 @@ class CollectionAdapter(object):
initiator=initiator)
def __getstate__(self):
return {'key': self.attr.key,
return {'key': self._key,
'owner_state': self.owner_state,
'data': self.data}
def __setstate__(self, d):
self.attr = getattr(d['owner_state'].obj().__class__, d['key']).impl
self._key = d['key']
self.owner_state = d['owner_state']
self._data = weakref.ref(d['data'])
+44 -1
View File
@@ -3,7 +3,7 @@ import pickle
import sqlalchemy as sa
from sqlalchemy.test import testing
from sqlalchemy.test.testing import assert_raises_message
from sqlalchemy import Integer, String, ForeignKey, exc
from sqlalchemy import Integer, String, ForeignKey, exc, MetaData
from sqlalchemy.test.schema import Table, Column
from sqlalchemy.orm import mapper, relationship, create_session, \
sessionmaker, attributes, interfaces,\
@@ -218,6 +218,49 @@ class PickleTest(_fixtures.FixtureTest):
u2 = pickle.loads(pickle.dumps(u1))
def test_collection_setstate(self):
"""test a particular cycle that requires CollectionAdapter
to not rely upon InstanceState to deserialize."""
global Child1, Child2, Parent, Screen
m = MetaData()
c1 = Table('c1', m,
Column('parent_id', String,
ForeignKey('p.id'), primary_key=True)
)
c2 = Table('c2', m,
Column('parent_id', String,
ForeignKey('p.id'), primary_key=True)
)
p = Table('p', m,
Column('id', String, primary_key=True)
)
class Child1(_base.ComparableEntity):
pass
class Child2(_base.ComparableEntity):
pass
class Parent(_base.ComparableEntity):
pass
mapper(Parent, p, properties={
'children1':relationship(Child1),
'children2':relationship(Child2)
})
mapper(Child1, c1)
mapper(Child2, c2)
class Screen(object):
def __init__(self, obj, parent=None):
self.obj = obj
self.parent = parent
obj = Parent()
screen1 = Screen(obj)
screen1.errors = [obj.children1, obj.children2]
screen2 = Screen(Child2(), screen1)
pickle.loads(pickle.dumps(screen2))
class PolymorphicDeferredTest(_base.MappedTest):
@classmethod