]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Allowed pickling of PropertyOption objects constructed with
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 26 Apr 2009 21:57:18 +0000 (21:57 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 26 Apr 2009 21:57:18 +0000 (21:57 +0000)
instrumented descriptors; previously, pickle errors would occur
when pickling an object which was loaded with a descriptor-based
option, such as query.options(eagerload(MyClass.foo)).

CHANGES
lib/sqlalchemy/orm/interfaces.py
test/orm/pickled.py

diff --git a/CHANGES b/CHANGES
index 34f0a9afbb0366e98b9bb98e7bedbb5d15d7b419..22d4c98434719b59c84b959f3f18dd0fe0519e98 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -19,7 +19,12 @@ CHANGES
       be assigned to a pending parent instance, otherwise modified
       events would not be fired correctly.  Set collection is now
       compatible with merge(), fixes [ticket:1352].
-
+    
+    - Allowed pickling of PropertyOption objects constructed with
+      instrumented descriptors; previously, pickle errors would occur 
+      when pickling an object which was loaded with a descriptor-based 
+      option, such as query.options(eagerload(MyClass.foo)).
+      
     - Lazy loader will not use get() if the "lazy load" SQL clause
       matches the clause used by get(), but contains some parameters
       hardcoded.  Previously the lazy strategy would fail with the
index 3b7507def64cb96b0ec3c2253454eed606b00a72..d36f51194e09aec35cd6bd08490998fca4e06f66 100644 (file)
@@ -682,6 +682,27 @@ class PropertyOption(MapperOption):
             else:
                 return None
 
+    def __getstate__(self):
+        d = self.__dict__.copy()
+        d['key'] = ret = []
+        for token in util.to_list(self.key):
+            if isinstance(token, PropComparator):
+                ret.append((token.mapper.class_, token.key))
+            else:
+                ret.append(token)
+        return d
+
+    def __setstate__(self, state):
+        ret = []
+        for key in state['key']:
+            if isinstance(key, tuple):
+                cls, propkey = key
+                ret.append(getattr(cls, propkey))
+            else:
+                ret.append(key)
+        state['key'] = tuple(ret)
+        self.__dict__ = state
+
     def __get_paths(self, query, raiseerr):
         path = None
         entity = None
index ca308bb5bee1b7f295ad19e974f4e4ca75a61dc8..878fe931e36bfbfc3eb74cbf7eb508ee688a806c 100644 (file)
@@ -99,7 +99,36 @@ class PickleTest(_fixtures.FixtureTest):
         self.assertEquals(ad.email_address, 'ed@bar.com')
         self.assertEquals(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
 
+    @testing.resolve_artifact_names
+    def test_options_with_descriptors(self):
+        mapper(User, users, properties={
+            'addresses':relation(Address, backref="user")
+        })
+        mapper(Address, addresses)
+        sess = create_session()
+        u1 = User(name='ed')
+        u1.addresses.append(Address(email_address='ed@bar.com'))
+        sess.add(u1)
+        sess.flush()
+        sess.expunge_all()
 
+        for opt in [
+            sa.orm.eagerload(User.addresses),
+            sa.orm.eagerload("addresses"),
+            sa.orm.defer("name"),
+            sa.orm.defer(User.name),
+            sa.orm.defer([User.name]),
+            sa.orm.eagerload("addresses", User.addresses),
+            sa.orm.eagerload(["addresses", User.addresses]),
+        ]:
+            opt2 = pickle.loads(pickle.dumps(opt))
+            self.assertEquals(opt.key, opt2.key)
+        
+        u1 = sess.query(User).options(opt).first()
+        
+        u2 = pickle.loads(pickle.dumps(u1))
+        
+        
 class PolymorphicDeferredTest(_base.MappedTest):
     def define_tables(self, metadata):
         Table('users', metadata,