summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2009-04-26 21:57:18 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2009-04-26 21:57:18 +0000
commit85f754751412fd48f915e7c3062689401a3723b8 (patch)
tree3b3d1c95d54a6b27a5b5ac0027be714950b4696e
parent1ec5704d142aded7505be4f7ef6ab02fc9410092 (diff)
downloadsqlalchemy-85f754751412fd48f915e7c3062689401a3723b8.tar.gz
- 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)).
-rw-r--r--CHANGES7
-rw-r--r--lib/sqlalchemy/orm/interfaces.py21
-rw-r--r--test/orm/pickled.py29
3 files changed, 56 insertions, 1 deletions
diff --git a/CHANGES b/CHANGES
index 34f0a9afb..22d4c9843 100644
--- 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
diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py
index 3b7507def..d36f51194 100644
--- a/lib/sqlalchemy/orm/interfaces.py
+++ b/lib/sqlalchemy/orm/interfaces.py
@@ -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
diff --git a/test/orm/pickled.py b/test/orm/pickled.py
index ca308bb5b..878fe931e 100644
--- a/test/orm/pickled.py
+++ b/test/orm/pickled.py
@@ -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,