diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2009-04-26 21:57:18 +0000 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2009-04-26 21:57:18 +0000 |
| commit | 85f754751412fd48f915e7c3062689401a3723b8 (patch) | |
| tree | 3b3d1c95d54a6b27a5b5ac0027be714950b4696e | |
| parent | 1ec5704d142aded7505be4f7ef6ab02fc9410092 (diff) | |
| download | sqlalchemy-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-- | CHANGES | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 21 | ||||
| -rw-r--r-- | test/orm/pickled.py | 29 |
3 files changed, 56 insertions, 1 deletions
@@ -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, |
