diff options
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/state.py | 4 | ||||
-rw-r--r-- | test/ext/test_mutable.py | 32 |
3 files changed, 38 insertions, 5 deletions
@@ -66,6 +66,13 @@ CHANGES setattr/delattr used on a hybrid that doesn't define fset or fdel. [ticket:2353] + - [bug] Fixed bug where unpickled object didn't + have enough of its state set up to work + correctly within the unpickle() event established + by the mutable object extension, if the object + needed ORM attribute access within + __eq__() or similar. [ticket:2362] + - sql - [feature] Added "false()" and "true()" expression constructs to sqlalchemy.sql namespace, though diff --git a/lib/sqlalchemy/orm/state.py b/lib/sqlalchemy/orm/state.py index 117341275..4803ecdc3 100644 --- a/lib/sqlalchemy/orm/state.py +++ b/lib/sqlalchemy/orm/state.py @@ -187,6 +187,10 @@ class InstanceState(object): if 'load_path' in state: self.load_path = interfaces.deserialize_path(state['load_path']) + # setup _sa_instance_state ahead of time so that + # unpickle events can access the object normally. + # see [ticket:2362] + manager.setup_instance(inst, self) manager.dispatch.unpickle(self, state) def initialize(self, key): diff --git a/test/ext/test_mutable.py b/test/ext/test_mutable.py index 129a460b0..60576f007 100644 --- a/test/ext/test_mutable.py +++ b/test/ext/test_mutable.py @@ -17,6 +17,13 @@ class Foo(fixtures.BasicEntity): class SubFoo(Foo): pass +class FooWithEq(object): + def __init__(self, **kw): + for k in kw: + setattr(self, k, kw[k]) + def __eq__(self, other): + return self.id == other.id + class _MutableDictTestBase(object): run_define_tables = 'each' @@ -317,12 +324,10 @@ class _CompositeTestBase(object): return self.x, self.y def __getstate__(self): - d = dict(self.__dict__) - d.pop('_parents', None) - return d + return self.x, self.y - #def __setstate__(self, state): - # self.x, self.y = state + def __setstate__(self, state): + self.x, self.y = state def __eq__(self, other): return isinstance(other, Point) and \ @@ -330,6 +335,23 @@ class _CompositeTestBase(object): other.y == self.y return Point +class MutableCompositesUnpickleTest(_CompositeTestBase, fixtures.MappedTest): + + @classmethod + def setup_mappers(cls): + foo = cls.tables.foo + + cls.Point = cls._type_fixture() + + mapper(FooWithEq, foo, properties={ + 'data':composite(cls.Point, foo.c.x, foo.c.y) + }) + + def test_unpickle_modified_eq(self): + u1 = FooWithEq(data=self.Point(3, 5)) + for loads, dumps in picklers(): + loads(dumps(u1)) + class MutableCompositesTest(_CompositeTestBase, fixtures.MappedTest): @classmethod |