~ubuntu-branches/debian/jessie/sqlalchemy/jessie

« back to all changes in this revision

Viewing changes to test/orm/test_legacy_mutable.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski, Jakub Wilk, Piotr Ożarowski
  • Date: 2013-07-06 20:53:52 UTC
  • mfrom: (1.4.23) (16.1.17 experimental)
  • Revision ID: package-import@ubuntu.com-20130706205352-ryppl1eto3illd79
Tags: 0.8.2-1
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Piotr Ożarowski ]
* New upstream release
* Upload to unstable
* Build depend on python3-all instead of -dev, extensions are not built for
  Python 3.X 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""Test the interaction of :class:`.MutableType` as well as the
2
 
``mutable=True`` flag with the ORM.
3
 
 
4
 
For new mutablity functionality, see test.ext.test_mutable.
5
 
 
6
 
"""
7
 
from test.lib.testing import eq_
8
 
import operator
9
 
from sqlalchemy.orm import mapper as orm_mapper
10
 
 
11
 
import sqlalchemy as sa
12
 
from sqlalchemy import Integer, String, ForeignKey
13
 
from test.lib import testing, pickleable
14
 
from test.lib.schema import Table, Column
15
 
from sqlalchemy.orm import mapper, create_session, Session, attributes
16
 
from test.lib.testing import eq_, ne_
17
 
from test.lib.util import gc_collect
18
 
from test.lib import fixtures
19
 
from test.orm import _fixtures
20
 
 
21
 
class MutableTypesTest(fixtures.MappedTest):
22
 
 
23
 
    @classmethod
24
 
    def define_tables(cls, metadata):
25
 
        Table('mutable_t', metadata,
26
 
            Column('id', Integer, primary_key=True,
27
 
                   test_needs_autoincrement=True),
28
 
            Column('data', sa.PickleType(mutable=True)),
29
 
            Column('val', sa.Unicode(30)))
30
 
 
31
 
    @classmethod
32
 
    def setup_classes(cls):
33
 
        class Foo(cls.Basic):
34
 
            pass
35
 
 
36
 
    @classmethod
37
 
    def setup_mappers(cls):
38
 
        mutable_t, Foo = cls.tables.mutable_t, cls.classes.Foo
39
 
 
40
 
        mapper(Foo, mutable_t)
41
 
 
42
 
    def test_modified_status(self):
43
 
        Foo = self.classes.Foo
44
 
 
45
 
        f1 = Foo(data = pickleable.Bar(4,5))
46
 
 
47
 
        session = Session()
48
 
        session.add(f1)
49
 
        session.commit()
50
 
 
51
 
        f2 = session.query(Foo).first()
52
 
        assert 'data' in sa.orm.attributes.instance_state(f2).unmodified
53
 
        eq_(f2.data, f1.data)
54
 
 
55
 
        f2.data.y = 19
56
 
        assert f2 in session.dirty
57
 
        assert 'data' not in sa.orm.attributes.instance_state(f2).unmodified
58
 
 
59
 
    def test_mutations_persisted(self):
60
 
        Foo = self.classes.Foo
61
 
 
62
 
        f1 = Foo(data = pickleable.Bar(4,5))
63
 
 
64
 
        session = Session()
65
 
        session.add(f1)
66
 
        session.commit()
67
 
        f1.data
68
 
        session.close()
69
 
 
70
 
        f2 = session.query(Foo).first()
71
 
        f2.data.y = 19
72
 
        session.commit()
73
 
        f2.data
74
 
        session.close()
75
 
 
76
 
        f3 = session.query(Foo).first()
77
 
        ne_(f3.data,f1.data)
78
 
        eq_(f3.data, pickleable.Bar(4, 19))
79
 
 
80
 
    def test_no_unnecessary_update(self):
81
 
        Foo = self.classes.Foo
82
 
 
83
 
        f1 = Foo(data = pickleable.Bar(4,5), val = u'hi')
84
 
 
85
 
        session = Session()
86
 
        session.add(f1)
87
 
        session.commit()
88
 
 
89
 
        self.sql_count_(0, session.commit)
90
 
 
91
 
        f1.val = u'someothervalue'
92
 
        self.assert_sql(testing.db, session.commit, [
93
 
            ("UPDATE mutable_t SET val=:val "
94
 
             "WHERE mutable_t.id = :mutable_t_id",
95
 
             {'mutable_t_id': f1.id, 'val': u'someothervalue'})])
96
 
 
97
 
        f1.val = u'hi'
98
 
        f1.data.x = 9
99
 
        self.assert_sql(testing.db, session.commit, [
100
 
            ("UPDATE mutable_t SET data=:data, val=:val "
101
 
             "WHERE mutable_t.id = :mutable_t_id",
102
 
             {'mutable_t_id': f1.id, 'val': u'hi', 'data':f1.data})])
103
 
 
104
 
    def test_mutated_state_resurrected(self):
105
 
        Foo = self.classes.Foo
106
 
 
107
 
        f1 = Foo(data = pickleable.Bar(4,5), val = u'hi')
108
 
 
109
 
        session = Session()
110
 
        session.add(f1)
111
 
        session.commit()
112
 
 
113
 
        f1.data.y = 19
114
 
        del f1
115
 
 
116
 
        gc_collect()
117
 
        assert len(session.identity_map) == 1
118
 
 
119
 
        session.commit()
120
 
 
121
 
        assert session.query(Foo).one().data == pickleable.Bar(4, 19)
122
 
 
123
 
    def test_mutated_plus_scalar_state_change_resurrected(self):
124
 
        """test that a non-mutable attribute event subsequent to
125
 
        a mutable event prevents the object from falling into
126
 
        resurrected state.
127
 
 
128
 
         """
129
 
 
130
 
        Foo = self.classes.Foo
131
 
 
132
 
        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
133
 
        session = Session()
134
 
        session.add(f1)
135
 
        session.commit()
136
 
        f1.data.x = 10
137
 
        f1.data.y = 15
138
 
        f1.val=u'some new val'
139
 
 
140
 
        assert sa.orm.attributes.instance_state(f1)._strong_obj is not None
141
 
 
142
 
        del f1
143
 
        session.commit()
144
 
        eq_(
145
 
            session.query(Foo.val).all(),
146
 
            [('some new val', )]
147
 
        )
148
 
 
149
 
    def test_non_mutated_state_not_resurrected(self):
150
 
        Foo = self.classes.Foo
151
 
 
152
 
        f1 = Foo(data = pickleable.Bar(4,5))
153
 
 
154
 
        session = Session()
155
 
        session.add(f1)
156
 
        session.commit()
157
 
 
158
 
        session = Session()
159
 
        f1 = session.query(Foo).first()
160
 
        del f1
161
 
        gc_collect()
162
 
 
163
 
        assert len(session.identity_map) == 0
164
 
        f1 = session.query(Foo).first()
165
 
        assert not attributes.instance_state(f1).modified
166
 
 
167
 
    def test_scalar_no_net_change_no_update(self):
168
 
        """Test that a no-net-change on a scalar attribute event
169
 
        doesn't cause an UPDATE for a mutable state.
170
 
 
171
 
         """
172
 
 
173
 
        Foo = self.classes.Foo
174
 
 
175
 
 
176
 
        f1 = Foo(val=u'hi')
177
 
 
178
 
        session = Session()
179
 
        session.add(f1)
180
 
        session.commit()
181
 
        session.close()
182
 
 
183
 
        f1 = session.query(Foo).first()
184
 
        f1.val = u'hi'
185
 
        self.sql_count_(0, session.commit)
186
 
 
187
 
    def test_expire_attribute_set(self):
188
 
        """test no SELECT emitted when assigning to an expired
189
 
        mutable attribute.
190
 
 
191
 
        """
192
 
 
193
 
        Foo = self.classes.Foo
194
 
 
195
 
 
196
 
        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
197
 
        session = Session()
198
 
        session.add(f1)
199
 
        session.commit()
200
 
 
201
 
        assert 'data' not in f1.__dict__
202
 
        def go():
203
 
            f1.data = pickleable.Bar(10, 15)
204
 
        self.sql_count_(0, go)
205
 
        session.commit()
206
 
 
207
 
        eq_(f1.data.x, 10)
208
 
 
209
 
    def test_expire_mutate(self):
210
 
        """test mutations are detected on an expired mutable
211
 
        attribute."""
212
 
 
213
 
        Foo = self.classes.Foo
214
 
 
215
 
 
216
 
        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
217
 
        session = Session()
218
 
        session.add(f1)
219
 
        session.commit()
220
 
 
221
 
        assert 'data' not in f1.__dict__
222
 
        def go():
223
 
            f1.data.x = 10
224
 
        self.sql_count_(1, go)
225
 
        session.commit()
226
 
 
227
 
        eq_(f1.data.x, 10)
228
 
 
229
 
    def test_deferred_attribute_set(self):
230
 
        """test no SELECT emitted when assigning to a deferred
231
 
        mutable attribute.
232
 
 
233
 
        """
234
 
 
235
 
        mutable_t, Foo = self.tables.mutable_t, self.classes.Foo
236
 
 
237
 
        sa.orm.clear_mappers()
238
 
        mapper(Foo, mutable_t, properties={
239
 
            'data':sa.orm.deferred(mutable_t.c.data)
240
 
        })
241
 
 
242
 
        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
243
 
        session = Session()
244
 
        session.add(f1)
245
 
        session.commit()
246
 
 
247
 
        session.close()
248
 
 
249
 
        f1 = session.query(Foo).first()
250
 
        def go():
251
 
            f1.data = pickleable.Bar(10, 15)
252
 
        self.sql_count_(0, go)
253
 
        session.commit()
254
 
 
255
 
        eq_(f1.data.x, 10)
256
 
 
257
 
    def test_deferred_mutate(self):
258
 
        """test mutations are detected on a deferred mutable
259
 
        attribute."""
260
 
 
261
 
        mutable_t, Foo = self.tables.mutable_t, self.classes.Foo
262
 
 
263
 
 
264
 
        sa.orm.clear_mappers()
265
 
        mapper(Foo, mutable_t, properties={
266
 
            'data':sa.orm.deferred(mutable_t.c.data)
267
 
        })
268
 
 
269
 
        f1 = Foo(data = pickleable.Bar(4, 5), val=u'some val')
270
 
        session = Session()
271
 
        session.add(f1)
272
 
        session.commit()
273
 
 
274
 
        session.close()
275
 
 
276
 
        f1 = session.query(Foo).first()
277
 
        def go():
278
 
            f1.data.x = 10
279
 
        self.sql_count_(1, go)
280
 
        session.commit()
281
 
 
282
 
        def go():
283
 
            eq_(f1.data.x, 10)
284
 
        self.sql_count_(1, go)
285
 
 
286
 
 
287
 
class PickledDictsTest(fixtures.MappedTest):
288
 
 
289
 
    @classmethod
290
 
    def define_tables(cls, metadata):
291
 
        Table('mutable_t', metadata,
292
 
            Column('id', Integer, primary_key=True,
293
 
                   test_needs_autoincrement=True),
294
 
            Column('data',
295
 
                sa.PickleType(comparator=operator.eq, mutable=True)))
296
 
 
297
 
    @classmethod
298
 
    def setup_classes(cls):
299
 
        class Foo(cls.Basic):
300
 
            pass
301
 
 
302
 
    @classmethod
303
 
    def setup_mappers(cls):
304
 
        mutable_t, Foo = cls.tables.mutable_t, cls.classes.Foo
305
 
 
306
 
        mapper(Foo, mutable_t)
307
 
 
308
 
    def test_dicts(self):
309
 
        """Dictionaries may not pickle the same way twice."""
310
 
 
311
 
        Foo = self.classes.Foo
312
 
 
313
 
 
314
 
        f1 = Foo()
315
 
        f1.data = [ {
316
 
            'personne': {'nom': u'Smith',
317
 
                         'pers_id': 1,
318
 
                         'prenom': u'john',
319
 
                         'civilite': u'Mr',
320
 
                         'int_3': False,
321
 
                         'int_2': False,
322
 
                         'int_1': u'23',
323
 
                         'VenSoir': True,
324
 
                         'str_1': u'Test',
325
 
                         'SamMidi': False,
326
 
                         'str_2': u'chien',
327
 
                         'DimMidi': False,
328
 
                         'SamSoir': True,
329
 
                         'SamAcc': False} } ]
330
 
 
331
 
        session = create_session(autocommit=False)
332
 
        session.add(f1)
333
 
        session.commit()
334
 
 
335
 
        self.sql_count_(0, session.commit)
336
 
 
337
 
        f1.data = [ {
338
 
            'personne': {'nom': u'Smith',
339
 
                         'pers_id': 1,
340
 
                         'prenom': u'john',
341
 
                         'civilite': u'Mr',
342
 
                         'int_3': False,
343
 
                         'int_2': False,
344
 
                         'int_1': u'23',
345
 
                         'VenSoir': True,
346
 
                         'str_1': u'Test',
347
 
                         'SamMidi': False,
348
 
                         'str_2': u'chien',
349
 
                         'DimMidi': False,
350
 
                         'SamSoir': True,
351
 
                         'SamAcc': False} } ]
352
 
 
353
 
        self.sql_count_(0, session.commit)
354
 
 
355
 
        f1.data[0]['personne']['VenSoir']= False
356
 
        self.sql_count_(1, session.commit)
357
 
 
358
 
        session.expunge_all()
359
 
        f = session.query(Foo).get(f1.id)
360
 
        eq_(f.data,
361
 
            [ {
362
 
            'personne': {'nom': u'Smith',
363
 
                         'pers_id': 1,
364
 
                         'prenom': u'john',
365
 
                         'civilite': u'Mr',
366
 
                         'int_3': False,
367
 
                         'int_2': False,
368
 
                         'int_1': u'23',
369
 
                         'VenSoir': False,
370
 
                         'str_1': u'Test',
371
 
                         'SamMidi': False,
372
 
                         'str_2': u'chien',
373
 
                         'DimMidi': False,
374
 
                         'SamSoir': True,
375
 
                         'SamAcc': False} } ])