PageRenderTime 62ms CodeModel.GetById 18ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

/SQLAlchemy-0.7.8/test/orm/test_pickled.py

#
Python | 552 lines | 454 code | 85 blank | 13 comment | 20 complexity | 0edfb2f6cdaf60fda2506194bc9f42d5 MD5 | raw file
  1from test.lib.testing import eq_
  2from sqlalchemy.util import pickle
  3import sqlalchemy as sa
  4from test.lib import testing
  5from test.lib.util import picklers
  6from test.lib.testing import assert_raises_message
  7from sqlalchemy import Integer, String, ForeignKey, exc, MetaData
  8from test.lib.schema import Table, Column
  9from sqlalchemy.orm import mapper, relationship, create_session, \
 10                            sessionmaker, attributes, interfaces,\
 11                            clear_mappers, exc as orm_exc,\
 12                            configure_mappers, Session, lazyload_all,\
 13                            lazyload, aliased
 14from sqlalchemy.orm.collections import attribute_mapped_collection, \
 15    column_mapped_collection
 16from test.lib import fixtures
 17from test.orm import _fixtures
 18from test.lib.pickleable import User, Address, Dingaling, Order, \
 19    Child1, Child2, Parent, Screen, EmailUser
 20
 21
 22class PickleTest(fixtures.MappedTest):
 23    @classmethod
 24    def define_tables(cls, metadata):
 25        Table('users', metadata,
 26              Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
 27              Column('name', String(30), nullable=False),
 28              test_needs_acid=True,
 29              test_needs_fk=True
 30        )
 31
 32        Table('addresses', metadata,
 33              Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
 34              Column('user_id', None, ForeignKey('users.id')),
 35              Column('email_address', String(50), nullable=False),
 36              test_needs_acid=True,
 37              test_needs_fk=True
 38        )
 39        Table('orders', metadata,
 40                  Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
 41                  Column('user_id', None, ForeignKey('users.id')),
 42                  Column('address_id', None, ForeignKey('addresses.id')),
 43                  Column('description', String(30)),
 44                  Column('isopen', Integer),
 45                  test_needs_acid=True,
 46                  test_needs_fk=True
 47        )
 48        Table("dingalings", metadata,
 49              Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
 50              Column('address_id', None, ForeignKey('addresses.id')),
 51              Column('data', String(30)),
 52              test_needs_acid=True,
 53              test_needs_fk=True
 54        )
 55
 56
 57    def test_transient(self):
 58        users, addresses = (self.tables.users,
 59                                self.tables.addresses)
 60
 61        mapper(User, users, properties={
 62            'addresses':relationship(Address, backref="user")
 63        })
 64        mapper(Address, addresses)
 65
 66        sess = create_session()
 67        u1 = User(name='ed')
 68        u1.addresses.append(Address(email_address='ed@bar.com'))
 69
 70        u2 = pickle.loads(pickle.dumps(u1))
 71        sess.add(u2)
 72        sess.flush()
 73
 74        sess.expunge_all()
 75
 76        eq_(u1, sess.query(User).get(u2.id))
 77
 78    def test_no_mappers(self):
 79        users = self.tables.users
 80
 81
 82        umapper = mapper(User, users)
 83        u1 = User(name='ed')
 84        u1_pickled = pickle.dumps(u1, -1)
 85
 86        clear_mappers()
 87
 88        assert_raises_message(
 89            orm_exc.UnmappedInstanceError,
 90            "Cannot deserialize object of type <class 'test.lib.pickleable.User'> - no mapper()",
 91            pickle.loads, u1_pickled)
 92
 93    def test_no_instrumentation(self):
 94        users = self.tables.users
 95
 96
 97        umapper = mapper(User, users)
 98        u1 = User(name='ed')
 99        u1_pickled = pickle.dumps(u1, -1)
100
101        clear_mappers()
102
103        umapper = mapper(User, users)
104
105        u1 = pickle.loads(u1_pickled)
106        # this fails unless the InstanceState
107        # compiles the mapper
108        eq_(str(u1), "User(name='ed')")
109
110    def test_serialize_path(self):
111        users, addresses = (self.tables.users,
112                                self.tables.addresses)
113
114        umapper = mapper(User, users, properties={
115            'addresses':relationship(Address, backref="user")
116        })
117        amapper = mapper(Address, addresses)
118
119        # this is a "relationship" path with mapper, key, mapper, key
120        p1 = (umapper, 'addresses', amapper, 'email_address')
121        eq_(
122            interfaces.deserialize_path(interfaces.serialize_path(p1)),
123            p1
124        )
125
126        # this is a "mapper" path with mapper, key, mapper, no key
127        # at the end.
128        p2 = (umapper, 'addresses', amapper, )
129        eq_(
130            interfaces.deserialize_path(interfaces.serialize_path(p2)),
131            p2
132        )
133
134        # test a blank path
135        p3 = ()
136        eq_(
137            interfaces.deserialize_path(interfaces.serialize_path(p3)),
138            p3
139        )
140
141    def test_class_deferred_cols(self):
142        addresses, users = (self.tables.addresses,
143                                self.tables.users)
144
145        mapper(User, users, properties={
146            'name':sa.orm.deferred(users.c.name),
147            'addresses':relationship(Address, backref="user")
148        })
149        mapper(Address, addresses, properties={
150            'email_address':sa.orm.deferred(addresses.c.email_address)
151        })
152        sess = create_session()
153        u1 = User(name='ed')
154        u1.addresses.append(Address(email_address='ed@bar.com'))
155        sess.add(u1)
156        sess.flush()
157        sess.expunge_all()
158        u1 = sess.query(User).get(u1.id)
159        assert 'name' not in u1.__dict__
160        assert 'addresses' not in u1.__dict__
161
162        u2 = pickle.loads(pickle.dumps(u1))
163        sess2 = create_session()
164        sess2.add(u2)
165        eq_(u2.name, 'ed')
166        eq_(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
167
168        u2 = pickle.loads(pickle.dumps(u1))
169        sess2 = create_session()
170        u2 = sess2.merge(u2, load=False)
171        eq_(u2.name, 'ed')
172        eq_(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
173
174    def test_instance_lazy_relation_loaders(self):
175        users, addresses = (self.tables.users,
176                                self.tables.addresses)
177
178        mapper(User, users, properties={
179            'addresses':relationship(Address, lazy='noload')
180        })
181        mapper(Address, addresses)
182
183        sess = Session()
184        u1 = User(name='ed', addresses=[
185                        Address(
186                            email_address='ed@bar.com', 
187                        )
188                ])
189
190        sess.add(u1)
191        sess.commit()
192        sess.close()
193
194        u1 = sess.query(User).options(
195                                lazyload(User.addresses)
196                            ).first()
197        u2 = pickle.loads(pickle.dumps(u1))
198
199        sess = Session()
200        sess.add(u2)
201        assert u2.addresses
202
203    def test_instance_deferred_cols(self):
204        users, addresses = (self.tables.users,
205                                self.tables.addresses)
206
207        mapper(User, users, properties={
208            'addresses':relationship(Address, backref="user")
209        })
210        mapper(Address, addresses)
211
212        sess = create_session()
213        u1 = User(name='ed')
214        u1.addresses.append(Address(email_address='ed@bar.com'))
215        sess.add(u1)
216        sess.flush()
217        sess.expunge_all()
218
219        u1 = sess.query(User).\
220                options(sa.orm.defer('name'), 
221                        sa.orm.defer('addresses.email_address')).\
222                        get(u1.id)
223        assert 'name' not in u1.__dict__
224        assert 'addresses' not in u1.__dict__
225
226        u2 = pickle.loads(pickle.dumps(u1))
227        sess2 = create_session()
228        sess2.add(u2)
229        eq_(u2.name, 'ed')
230        assert 'addresses' not in u2.__dict__
231        ad = u2.addresses[0]
232        assert 'email_address' not in ad.__dict__
233        eq_(ad.email_address, 'ed@bar.com')
234        eq_(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
235
236        u2 = pickle.loads(pickle.dumps(u1))
237        sess2 = create_session()
238        u2 = sess2.merge(u2, load=False)
239        eq_(u2.name, 'ed')
240        assert 'addresses' not in u2.__dict__
241        ad = u2.addresses[0]
242
243        # mapper options now transmit over merge(),
244        # new as of 0.6, so email_address is deferred.
245        assert 'email_address' not in ad.__dict__
246
247        eq_(ad.email_address, 'ed@bar.com')
248        eq_(u2, User(name='ed', addresses=[Address(email_address='ed@bar.com')]))
249
250    def test_pickle_protocols(self):
251        users, addresses = (self.tables.users,
252                                self.tables.addresses)
253
254        mapper(User, users, properties={
255            'addresses':relationship(Address, backref="user")
256        })
257        mapper(Address, addresses)
258
259        sess = sessionmaker()()
260        u1 = User(name='ed')
261        u1.addresses.append(Address(email_address='ed@bar.com'))
262        sess.add(u1)
263        sess.commit()
264
265        u1 = sess.query(User).first()
266        u1.addresses
267
268        for loads, dumps in picklers():
269            u2 = loads(dumps(u1))
270            eq_(u1, u2)
271
272
273    def test_options_with_descriptors(self):
274        users, addresses, dingalings = (self.tables.users,
275                                self.tables.addresses,
276                                self.tables.dingalings)
277
278        mapper(User, users, properties={
279            'addresses':relationship(Address, backref="user")
280        })
281        mapper(Address, addresses, properties={
282            'dingaling':relationship(Dingaling)
283        })
284        mapper(Dingaling, dingalings)
285        sess = create_session()
286        u1 = User(name='ed')
287        u1.addresses.append(Address(email_address='ed@bar.com'))
288        sess.add(u1)
289        sess.flush()
290        sess.expunge_all()
291
292        for opt in [
293            sa.orm.joinedload(User.addresses),
294            sa.orm.joinedload("addresses"),
295            sa.orm.defer("name"),
296            sa.orm.defer(User.name),
297            sa.orm.joinedload("addresses", Address.dingaling),
298        ]:
299            opt2 = pickle.loads(pickle.dumps(opt))
300            eq_(opt.key, opt2.key)
301
302        u1 = sess.query(User).options(opt).first()
303        u2 = pickle.loads(pickle.dumps(u1))
304
305    def test_collection_setstate(self):
306        """test a particular cycle that requires CollectionAdapter 
307        to not rely upon InstanceState to deserialize."""
308
309        m = MetaData()
310        c1 = Table('c1', m, 
311            Column('parent_id', String, 
312                        ForeignKey('p.id'), primary_key=True)
313        )
314        c2 = Table('c2', m,
315            Column('parent_id', String, 
316                        ForeignKey('p.id'), primary_key=True)
317        )
318        p = Table('p', m,
319            Column('id', String, primary_key=True)
320        )
321
322        mapper(Parent, p, properties={
323            'children1':relationship(Child1),
324            'children2':relationship(Child2)
325        })
326        mapper(Child1, c1)
327        mapper(Child2, c2)
328
329        obj = Parent()
330        screen1 = Screen(obj)
331        screen1.errors = [obj.children1, obj.children2]
332        screen2 = Screen(Child2(), screen1)
333        pickle.loads(pickle.dumps(screen2))
334
335    def test_exceptions(self):
336        class Foo(object):
337            pass
338        users = self.tables.users
339        mapper(User, users)
340
341        for sa_exc in (
342            orm_exc.UnmappedInstanceError(Foo()),
343            orm_exc.UnmappedClassError(Foo),
344            orm_exc.ObjectDeletedError(attributes.instance_state(User())),
345        ):
346            for loads, dumps in picklers():
347                repickled = loads(dumps(sa_exc))
348                eq_(repickled.args[0], sa_exc.args[0])
349
350    def test_attribute_mapped_collection(self):
351        users, addresses = self.tables.users, self.tables.addresses
352
353        mapper(User, users, properties={
354            'addresses':relationship(
355                            Address, 
356                            collection_class=
357                            attribute_mapped_collection('email_address')
358                        )
359        })
360        mapper(Address, addresses)
361        u1 = User()
362        u1.addresses = {"email1":Address(email_address="email1")}
363        for loads, dumps in picklers():
364            repickled = loads(dumps(u1))
365            eq_(u1.addresses, repickled.addresses)
366            eq_(repickled.addresses['email1'], 
367                    Address(email_address="email1"))
368
369    def test_column_mapped_collection(self):
370        users, addresses = self.tables.users, self.tables.addresses
371
372        mapper(User, users, properties={
373            'addresses':relationship(
374                            Address, 
375                            collection_class=
376                            column_mapped_collection(
377                                addresses.c.email_address)
378                        )
379        })
380        mapper(Address, addresses)
381        u1 = User()
382        u1.addresses = {
383            "email1":Address(email_address="email1"),
384            "email2":Address(email_address="email2")
385        }
386        for loads, dumps in picklers():
387            repickled = loads(dumps(u1))
388            eq_(u1.addresses, repickled.addresses)
389            eq_(repickled.addresses['email1'], 
390                    Address(email_address="email1"))
391
392    def test_composite_column_mapped_collection(self):
393        users, addresses = self.tables.users, self.tables.addresses
394
395        mapper(User, users, properties={
396            'addresses':relationship(
397                            Address, 
398                            collection_class=
399                            column_mapped_collection([
400                                addresses.c.id,
401                                addresses.c.email_address])
402                        )
403        })
404        mapper(Address, addresses)
405        u1 = User()
406        u1.addresses = {
407            (1, "email1"):Address(id=1, email_address="email1"),
408            (2, "email2"):Address(id=2, email_address="email2")
409        }
410        for loads, dumps in picklers():
411            repickled = loads(dumps(u1))
412            eq_(u1.addresses, repickled.addresses)
413            eq_(repickled.addresses[(1, 'email1')], 
414                    Address(id=1, email_address="email1"))
415
416class PolymorphicDeferredTest(fixtures.MappedTest):
417    @classmethod
418    def define_tables(cls, metadata):
419        Table('users', metadata,
420            Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
421            Column('name', String(30)),
422            Column('type', String(30)))
423        Table('email_users', metadata,
424            Column('id', Integer, ForeignKey('users.id'), primary_key=True),
425            Column('email_address', String(30)))
426
427
428    def test_polymorphic_deferred(self):
429        email_users, users = (self.tables.email_users,
430                                self.tables.users,
431                                )
432
433        mapper(User, users, polymorphic_identity='user', polymorphic_on=users.c.type)
434        mapper(EmailUser, email_users, inherits=User, polymorphic_identity='emailuser')
435
436        eu = EmailUser(name="user1", email_address='foo@bar.com')
437        sess = create_session()
438        sess.add(eu)
439        sess.flush()
440        sess.expunge_all()
441
442        eu = sess.query(User).first()
443        eu2 = pickle.loads(pickle.dumps(eu))
444        sess2 = create_session()
445        sess2.add(eu2)
446        assert 'email_address' not in eu2.__dict__
447        eq_(eu2.email_address, 'foo@bar.com')
448
449class TupleLabelTest(_fixtures.FixtureTest):
450    @classmethod
451    def setup_classes(cls):
452        pass
453
454    @classmethod
455    def setup_mappers(cls):
456        users, addresses, orders = cls.tables.users, cls.tables.addresses, cls.tables.orders
457        mapper(User, users, properties={
458            'addresses':relationship(Address, backref='user', order_by=addresses.c.id),
459            'orders':relationship(Order, backref='user', order_by=orders.c.id), # o2m, m2o
460        })
461        mapper(Address, addresses)
462        mapper(Order, orders, properties={
463            'address':relationship(Address),  # m2o
464        })
465
466    def test_tuple_labeling(self):
467        users = self.tables.users
468        sess = create_session()
469
470        # test pickle + all the protocols !
471        for pickled in False, -1, 0, 1, 2:
472            for row in sess.query(User, Address).join(User.addresses).all():
473                if pickled is not False:
474                    row = pickle.loads(pickle.dumps(row, pickled))
475
476                eq_(row.keys(), ['User', 'Address'])
477                eq_(row.User, row[0])
478                eq_(row.Address, row[1])
479
480            for row in sess.query(User.name, User.id.label('foobar')):
481                if pickled is not False:
482                    row = pickle.loads(pickle.dumps(row, pickled))
483                eq_(row.keys(), ['name', 'foobar'])
484                eq_(row.name, row[0])
485                eq_(row.foobar, row[1])
486
487            for row in sess.query(User).values(User.name, User.id.label('foobar')):
488                if pickled is not False:
489                    row = pickle.loads(pickle.dumps(row, pickled))
490                eq_(row.keys(), ['name', 'foobar'])
491                eq_(row.name, row[0])
492                eq_(row.foobar, row[1])
493
494            oalias = aliased(Order)
495            for row in sess.query(User, oalias).join(User.orders).all():
496                if pickled is not False:
497                    row = pickle.loads(pickle.dumps(row, pickled))
498                eq_(row.keys(), ['User'])
499                eq_(row.User, row[0])
500
501            oalias = aliased(Order, name='orders')
502            for row in sess.query(User, oalias).join(oalias, User.orders).all():
503                if pickled is not False:
504                    row = pickle.loads(pickle.dumps(row, pickled))
505                eq_(row.keys(), ['User', 'orders'])
506                eq_(row.User, row[0])
507                eq_(row.orders, row[1])
508
509            # test here that first col is not labeled, only
510            # one name in keys, matches correctly
511            for row in sess.query(User.name + 'hoho', User.name):
512                eq_(row.keys(), ['name'])
513                eq_(row[0], row.name + 'hoho')
514
515            if pickled is not False:
516                ret = sess.query(User, Address).join(User.addresses).all()
517                pickle.loads(pickle.dumps(ret, pickled))
518
519class CustomSetupTeardownTest(fixtures.MappedTest):
520    @classmethod
521    def define_tables(cls, metadata):
522        Table('users', metadata,
523              Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
524              Column('name', String(30), nullable=False),
525              test_needs_acid=True,
526              test_needs_fk=True
527        )
528
529        Table('addresses', metadata,
530              Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
531              Column('user_id', None, ForeignKey('users.id')),
532              Column('email_address', String(50), nullable=False),
533              test_needs_acid=True,
534              test_needs_fk=True
535        )
536    def test_rebuild_state(self):
537        """not much of a 'test', but illustrate how to 
538        remove instance-level state before pickling.
539
540        """
541
542        users = self.tables.users
543
544        mapper(User, users)
545
546        u1 = User()
547        attributes.manager_of_class(User).teardown_instance(u1)
548        assert not u1.__dict__
549        u2 = pickle.loads(pickle.dumps(u1))
550        attributes.manager_of_class(User).setup_instance(u2)
551        assert attributes.instance_state(u2)
552