]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [bug] Fixed bug where unpickled object didn't
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 18:48:05 +0000 (13:48 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 18:48:05 +0000 (13:48 -0500)
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]

CHANGES
lib/sqlalchemy/orm/state.py
test/ext/test_mutable.py

diff --git a/CHANGES b/CHANGES
index afe9168cd807e62a349d7d4ede969fbe820fcbb0..e1c9969df73dd173ec45c675e444fc6169f2553b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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
index 117341275a5d5947befec58b331a6811456d99fa..4803ecdc3d14cab77ece3046cb683bbad9548830 100644 (file)
@@ -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):
index 129a460b0c19e330d9fd1bff0f4fab38bc5c771f..60576f007886c0edc5b1a9666b0aac621bf470cc 100644 (file)
@@ -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