1
from test.lib.testing import eq_, assert_raises, \
2
assert_raises_message, assert_warnings
3
from test.lib.util import gc_collect
4
from test.lib import pickleable
1
from sqlalchemy.testing import eq_, assert_raises, \
3
from sqlalchemy.testing.util import gc_collect
4
from sqlalchemy.testing import pickleable
5
5
from sqlalchemy.util import pickle
7
7
from sqlalchemy.orm import create_session, sessionmaker, attributes, \
8
8
make_transient, Session
9
9
import sqlalchemy as sa
10
from test.lib import engines, testing, config
10
from sqlalchemy.testing import engines, config
11
from sqlalchemy import testing
11
12
from sqlalchemy import Integer, String, Sequence
12
from test.lib.schema import Table, Column
13
from sqlalchemy.testing.schema import Table, Column
13
14
from sqlalchemy.orm import mapper, relationship, backref, joinedload, \
14
exc as orm_exc, object_session
15
exc as orm_exc, object_session, was_deleted
15
16
from sqlalchemy.util import pypy
16
from test.lib import fixtures
17
from test.lib import fixtures
17
from sqlalchemy.testing import fixtures
18
18
from test.orm import _fixtures
19
from sqlalchemy import event, ForeignKey
20
class SessionTest(_fixtures.FixtureTest):
21
class BindTest(_fixtures.FixtureTest):
23
def test_no_close_on_flush(self):
24
"""Flush() doesn't close a connection the session didn't open"""
26
User, users = self.classes.User, self.tables.users
28
c = testing.db.connect()
29
c.execute("select * from users")
32
s = create_session(bind=c)
33
s.add(User(name='first'))
35
c.execute("select * from users")
38
"""close() doesn't close a connection the session didn't open"""
40
User, users = self.classes.User, self.tables.users
42
c = testing.db.connect()
43
c.execute("select * from users")
46
s = create_session(bind=c)
47
s.add(User(name='first'))
49
c.execute("select * from users")
51
c.execute("select * from users")
53
def test_object_session_raises(self):
54
User = self.classes.User
57
orm_exc.UnmappedInstanceError,
63
orm_exc.UnmappedInstanceError,
68
@testing.requires.sequences
69
def test_sequence_execute(self):
70
seq = Sequence("some_sequence")
71
seq.create(testing.db)
73
sess = create_session(bind=testing.db)
74
eq_(sess.execute(seq), 1)
80
@engines.close_open_connections
81
24
def test_mapped_binds(self):
82
25
Address, addresses, users, User = (self.classes.Address,
83
26
self.tables.addresses,
177
117
assert len(session.query(User).filter_by(name='Johnny').all()) == 0
120
def test_bind_arguments(self):
121
users, Address, addresses, User = (self.tables.users,
122
self.classes.Address,
123
self.tables.addresses,
127
mapper(Address, addresses)
129
e1 = engines.testing_engine()
130
e2 = engines.testing_engine()
131
e3 = engines.testing_engine()
134
sess.bind_mapper(User, e1)
135
sess.bind_mapper(Address, e2)
137
assert sess.connection().engine is e3
138
assert sess.connection(bind=e1).engine is e1
139
assert sess.connection(mapper=Address, bind=e1).engine is e1
140
assert sess.connection(mapper=Address).engine is e2
141
assert sess.connection(clause=addresses.select()).engine is e2
142
assert sess.connection(mapper=User,
143
clause=addresses.select()).engine is e1
144
assert sess.connection(mapper=User,
145
clause=addresses.select(),
146
bind=e2).engine is e2
150
@engines.close_open_connections
151
def test_bound_connection(self):
152
users, User = self.tables.users, self.classes.User
155
c = testing.db.connect()
156
sess = create_session(bind=c)
158
transaction = sess.transaction
162
assert transaction._connection_for_bind(testing.db) \
163
is transaction._connection_for_bind(c) is c
165
assert_raises_message(sa.exc.InvalidRequestError,
166
'Session already has a Connection '
168
transaction._connection_for_bind,
169
testing.db.connect())
170
transaction.rollback()
171
assert len(sess.query(User).all()) == 0
174
def test_bound_connection_transactional(self):
175
User, users = self.classes.User, self.tables.users
178
c = testing.db.connect()
180
sess = create_session(bind=c, autocommit=False)
185
assert not c.in_transaction()
186
assert c.scalar("select count(1) from users") == 0
188
sess = create_session(bind=c, autocommit=False)
193
assert not c.in_transaction()
194
assert c.scalar("select count(1) from users") == 1
195
c.execute("delete from users")
196
assert c.scalar("select count(1) from users") == 0
198
c = testing.db.connect()
201
sess = create_session(bind=c, autocommit=True)
205
assert c.in_transaction()
207
assert not c.in_transaction()
208
assert c.scalar("select count(1) from users") == 1
210
class ExecutionTest(_fixtures.FixtureTest):
213
@testing.requires.sequences
214
def test_sequence_execute(self):
215
seq = Sequence("some_sequence")
216
seq.create(testing.db)
218
sess = create_session(bind=testing.db)
219
eq_(sess.execute(seq), 1)
223
def test_textual_execute(self):
224
"""test that Session.execute() converts to text()"""
226
users = self.tables.users
229
sess = create_session(bind=self.metadata.bind)
230
users.insert().execute(id=7, name='jack')
232
# use :bindparam style
233
eq_(sess.execute("select * from users where id=:id",
234
{'id': 7}).fetchall(),
238
# use :bindparam style
239
eq_(sess.scalar("select id from users where id=:id",
243
def test_parameter_execute(self):
244
users = self.tables.users
245
sess = Session(bind=testing.db)
246
sess.execute(users.insert(), [
247
{"id": 7, "name": "u7"},
248
{"id": 8, "name": "u8"}
251
sess.execute(users.insert(), {"id": 9, "name": "u9"})
253
sess.execute(sa.select([users.c.id]).\
254
order_by(users.c.id)).fetchall(),
255
[(7, ), (8, ), (9, )]
259
class TransScopingTest(_fixtures.FixtureTest):
262
def test_no_close_on_flush(self):
263
"""Flush() doesn't close a connection the session didn't open"""
265
User, users = self.classes.User, self.tables.users
267
c = testing.db.connect()
268
c.execute("select * from users")
271
s = create_session(bind=c)
272
s.add(User(name='first'))
274
c.execute("select * from users")
276
def test_close(self):
277
"""close() doesn't close a connection the session didn't open"""
279
User, users = self.classes.User, self.tables.users
281
c = testing.db.connect()
282
c.execute("select * from users")
285
s = create_session(bind=c)
286
s.add(User(name='first'))
288
c.execute("select * from users")
290
c.execute("select * from users")
180
292
@testing.requires.independent_connections
181
293
@engines.close_open_connections
182
294
def test_transaction(self):
430
564
assert not sess.is_active
432
def test_textual_execute(self):
433
"""test that Session.execute() converts to text()"""
435
users = self.tables.users
438
sess = create_session(bind=self.metadata.bind)
439
users.insert().execute(id=7, name='jack')
441
# use :bindparam style
442
eq_(sess.execute("select * from users where id=:id",
443
{'id':7}).fetchall(),
447
# use :bindparam style
448
eq_(sess.scalar("select id from users where id=:id",
452
def test_parameter_execute(self):
453
users = self.tables.users
454
sess = Session(bind=testing.db)
455
sess.execute(users.insert(), [
456
{"id": 7, "name": "u7"},
457
{"id": 8, "name": "u8"}
460
sess.execute(users.insert(), {"id": 9, "name": "u9"})
462
sess.execute(sa.select([users.c.id]).\
463
order_by(users.c.id)).fetchall(),
464
[(7, ), (8, ), (9, )]
468
@engines.close_open_connections
469
def test_bound_connection(self):
470
users, User = self.tables.users, self.classes.User
473
c = testing.db.connect()
474
sess = create_session(bind=c)
476
transaction = sess.transaction
480
assert transaction._connection_for_bind(testing.db) \
481
is transaction._connection_for_bind(c) is c
483
assert_raises_message(sa.exc.InvalidRequestError,
484
'Session already has a Connection '
486
transaction._connection_for_bind,
487
testing.db.connect())
488
transaction.rollback()
489
assert len(sess.query(User).all()) == 0
492
def test_bound_connection_transactional(self):
493
User, users = self.classes.User, self.tables.users
496
c = testing.db.connect()
498
sess = create_session(bind=c, autocommit=False)
503
assert not c.in_transaction()
504
assert c.scalar("select count(1) from users") == 0
506
sess = create_session(bind=c, autocommit=False)
511
assert not c.in_transaction()
512
assert c.scalar("select count(1) from users") == 1
513
c.execute("delete from users")
514
assert c.scalar("select count(1) from users") == 0
516
c = testing.db.connect()
519
sess = create_session(bind=c, autocommit=True)
523
assert c.in_transaction()
525
assert not c.in_transaction()
526
assert c.scalar("select count(1) from users") == 1
528
def test_bind_arguments(self):
529
users, Address, addresses, User = (self.tables.users,
530
self.classes.Address,
531
self.tables.addresses,
535
mapper(Address, addresses)
537
e1 = engines.testing_engine()
538
e2 = engines.testing_engine()
539
e3 = engines.testing_engine()
542
sess.bind_mapper(User, e1)
543
sess.bind_mapper(Address, e2)
545
assert sess.connection().engine is e3
546
assert sess.connection(bind=e1).engine is e1
547
assert sess.connection(mapper=Address, bind=e1).engine is e1
548
assert sess.connection(mapper=Address).engine is e2
549
assert sess.connection(clause=addresses.select()).engine is e2
550
assert sess.connection(mapper=User,
551
clause=addresses.select()).engine is e1
552
assert sess.connection(mapper=User,
553
clause=addresses.select(),
554
bind=e2).engine is e2
558
567
@engines.close_open_connections
559
568
def test_add_delete(self):
703
646
assert_raises(AssertionError, s.identity_map.add,
704
647
sa.orm.attributes.instance_state(u2))
707
def test_weakref_with_cycles_o2m(self):
708
Address, addresses, users, User = (self.classes.Address,
709
self.tables.addresses,
714
mapper(User, users, properties={
715
"addresses":relationship(Address, backref="user")
717
mapper(Address, addresses)
718
s.add(User(name="ed", addresses=[Address(email_address="ed1")]))
721
user = s.query(User).options(joinedload(User.addresses)).one()
722
user.addresses[0].user # lazyload
723
eq_(user, User(name="ed", addresses=[Address(email_address="ed1")]))
727
assert len(s.identity_map) == 0
729
user = s.query(User).options(joinedload(User.addresses)).one()
730
user.addresses[0].email_address='ed2'
731
user.addresses[0].user # lazyload
734
assert len(s.identity_map) == 2
737
user = s.query(User).options(joinedload(User.addresses)).one()
738
eq_(user, User(name="ed", addresses=[Address(email_address="ed2")]))
740
def test_weakref_with_cycles_o2o(self):
741
Address, addresses, users, User = (self.classes.Address,
742
self.tables.addresses,
747
mapper(User, users, properties={
748
"address":relationship(Address, backref="user", uselist=False)
750
mapper(Address, addresses)
751
s.add(User(name="ed", address=Address(email_address="ed1")))
754
user = s.query(User).options(joinedload(User.address)).one()
756
eq_(user, User(name="ed", address=Address(email_address="ed1")))
760
assert len(s.identity_map) == 0
762
user = s.query(User).options(joinedload(User.address)).one()
763
user.address.email_address='ed2'
764
user.address.user # lazyload
768
assert len(s.identity_map) == 2
771
user = s.query(User).options(joinedload(User.address)).one()
772
eq_(user, User(name="ed", address=Address(email_address="ed2")))
774
@testing.uses_deprecated()
775
def test_strong_ref(self):
776
users, User = self.tables.users, self.classes.User
778
s = create_session(weak_identity_map=False)
782
s.add(User(name='u1'))
784
user = s.query(User).one()
788
assert len(s.identity_map) == 1
790
user = s.query(User).one()
791
assert not s.identity_map._modified
793
assert s.identity_map._modified
795
eq_(users.select().execute().fetchall(), [(user.id, 'u2')])
797
@testing.uses_deprecated()
798
@testing.fails_if(lambda: pypy, "pypy has a real GC")
799
@testing.fails_on('+zxjdbc', 'http://www.sqlalchemy.org/trac/ticket/1473')
800
def test_prune(self):
801
users, User = self.tables.users, self.classes.User
803
s = create_session(weak_identity_map=False)
806
for o in [User(name='u%s' % x) for x in xrange(10)]:
808
# o is still live after this loop...
810
self.assert_(len(s.identity_map) == 0)
811
self.assert_(s.prune() == 0)
814
self.assert_(s.prune() == 9)
815
self.assert_(len(s.identity_map) == 1)
819
self.assert_(s.prune() == 1)
820
self.assert_(len(s.identity_map) == 0)
822
u = s.query(User).get(id)
823
self.assert_(s.prune() == 0)
824
self.assert_(len(s.identity_map) == 1)
827
self.assert_(s.prune() == 0)
828
self.assert_(len(s.identity_map) == 1)
830
self.assert_(s.prune() == 1)
831
self.assert_(len(s.identity_map) == 0)
833
s.add(User(name='x'))
834
self.assert_(s.prune() == 0)
835
self.assert_(len(s.identity_map) == 0)
837
self.assert_(len(s.identity_map) == 1)
838
self.assert_(s.prune() == 1)
839
self.assert_(len(s.identity_map) == 0)
841
u = s.query(User).get(id)
844
self.assert_(s.prune() == 0)
845
self.assert_(len(s.identity_map) == 1)
847
self.assert_(s.prune() == 0)
848
self.assert_(len(s.identity_map) == 0)
851
649
def test_pickled_update(self):
852
650
users, User = self.tables.users, pickleable.User
931
729
sess.add_all([User(name='u1'), User(name='u2'), User(name='u3')])
732
# TODO: what are we testing here ? that iteritems() can
733
# withstand a change? should this be
734
# more directly attempting to manipulate the identity_map ?
934
735
u1, u2, u3 = sess.query(User).all()
935
736
for i, (key, value) in enumerate(sess.identity_map.iteritems()):
940
def test_auto_detach_on_gc_session(self):
741
def _test_extra_dirty_state(self):
742
users, User = self.tables.users, self.classes.User
743
m = mapper(User, users)
747
@event.listens_for(m, "after_update")
748
def e(mapper, conn, target):
749
sess = object_session(target)
750
for entry in sess.identity_map.values():
753
a1, a2 = User(name="1"), User(name="2")
761
def test_extra_dirty_state_post_flush_warning(self):
762
s, a1, a2 = self._test_extra_dirty_state()
763
assert_raises_message(
765
"Attribute history events accumulated on 1 previously "
770
def test_extra_dirty_state_post_flush_state(self):
771
s, a1, a2 = self._test_extra_dirty_state()
773
@event.listens_for(s, "after_flush_postexec")
775
canary.append(bool(sess.identity_map._modified))
777
@testing.emits_warning("Attribute")
783
def test_deleted_expunged(self):
941
784
users, User = self.tables.users, self.classes.User
943
786
mapper(User, users)
951
# can't add u1 to Session,
952
# already belongs to u2
954
assert_raises_message(
955
sa.exc.InvalidRequestError,
956
r".*is already attached to session",
960
# garbage collect sess
964
# s2 lets it in now despite u1 having
969
class SessionDataTest(_fixtures.FixtureTest):
970
def test_expunge_cascade(self):
971
Address, addresses, users, User = (self.classes.Address,
972
self.tables.addresses,
976
mapper(Address, addresses)
977
mapper(User, users, properties={
978
'addresses':relationship(Address,
979
backref=backref("user", cascade="all"),
982
session = create_session()
983
u = session.query(User).filter_by(id=7).one()
985
# get everything to load in both directions
986
print [a.user for a in u.addresses]
988
# then see if expunge fails
991
assert sa.orm.object_session(u) is None
992
assert sa.orm.attributes.instance_state(u).session_id is None
993
for a in u.addresses:
994
assert sa.orm.object_session(a) is None
995
assert sa.orm.attributes.instance_state(a).session_id is None
788
sess.add(User(name='x'))
791
u1 = sess.query(User).first()
794
assert not was_deleted(u1)
797
assert was_deleted(u1)
798
assert u1 not in sess
799
assert object_session(u1) is sess
802
assert object_session(u1) is None
804
class SessionStateWFixtureTest(_fixtures.FixtureTest):
997
806
def test_autoflush_rollback(self):
998
807
Address, addresses, users, User = (self.classes.Address,
1020
829
# pending objects dont get expired
1021
830
assert newad.email_address == 'a new address'
832
def test_expunge_cascade(self):
833
Address, addresses, users, User = (self.classes.Address,
834
self.tables.addresses,
838
mapper(Address, addresses)
839
mapper(User, users, properties={
840
'addresses': relationship(Address,
841
backref=backref("user", cascade="all"),
844
session = create_session()
845
u = session.query(User).filter_by(id=7).one()
847
# get everything to load in both directions
848
print [a.user for a in u.addresses]
850
# then see if expunge fails
853
assert sa.orm.object_session(u) is None
854
assert sa.orm.attributes.instance_state(u).session_id is None
855
for a in u.addresses:
856
assert sa.orm.object_session(a) is None
857
assert sa.orm.attributes.instance_state(a).session_id is None
860
class NoCyclesOnTransientDetachedTest(_fixtures.FixtureTest):
861
"""Test the instance_state._strong_obj link that it
862
is present only on persistent/pending objects and never
869
mapper(self.classes.User, self.tables.users)
871
def _assert_modified(self, u1):
872
assert sa.orm.attributes.instance_state(u1).modified
874
def _assert_not_modified(self, u1):
875
assert not sa.orm.attributes.instance_state(u1).modified
877
def _assert_cycle(self, u1):
878
assert sa.orm.attributes.instance_state(u1)._strong_obj is not None
880
def _assert_no_cycle(self, u1):
881
assert sa.orm.attributes.instance_state(u1)._strong_obj is None
883
def _persistent_fixture(self):
884
User = self.classes.User
892
def test_transient(self):
893
User = self.classes.User
896
self._assert_no_cycle(u1)
897
self._assert_modified(u1)
899
def test_transient_to_pending(self):
900
User = self.classes.User
903
self._assert_modified(u1)
904
self._assert_no_cycle(u1)
907
self._assert_cycle(u1)
909
self._assert_no_cycle(u1)
910
self._assert_not_modified(u1)
912
def test_dirty_persistent_to_detached_via_expunge(self):
913
sess, u1 = self._persistent_fixture()
914
u1.name = 'edchanged'
915
self._assert_cycle(u1)
917
self._assert_no_cycle(u1)
919
def test_dirty_persistent_to_detached_via_close(self):
920
sess, u1 = self._persistent_fixture()
921
u1.name = 'edchanged'
922
self._assert_cycle(u1)
924
self._assert_no_cycle(u1)
926
def test_clean_persistent_to_detached_via_close(self):
927
sess, u1 = self._persistent_fixture()
928
self._assert_no_cycle(u1)
929
self._assert_not_modified(u1)
931
u1.name = 'edchanged'
932
self._assert_modified(u1)
933
self._assert_no_cycle(u1)
935
def test_detached_to_dirty_deleted(self):
936
sess, u1 = self._persistent_fixture()
938
u1.name = 'edchanged'
939
self._assert_no_cycle(u1)
941
self._assert_cycle(u1)
943
def test_detached_to_dirty_persistent(self):
944
sess, u1 = self._persistent_fixture()
946
u1.name = 'edchanged'
947
self._assert_modified(u1)
948
self._assert_no_cycle(u1)
950
self._assert_cycle(u1)
951
self._assert_modified(u1)
953
def test_detached_to_clean_persistent(self):
954
sess, u1 = self._persistent_fixture()
956
self._assert_no_cycle(u1)
957
self._assert_not_modified(u1)
959
self._assert_no_cycle(u1)
960
self._assert_not_modified(u1)
962
def test_move_persistent_clean(self):
963
sess, u1 = self._persistent_fixture()
967
self._assert_no_cycle(u1)
968
self._assert_not_modified(u1)
970
def test_move_persistent_dirty(self):
971
sess, u1 = self._persistent_fixture()
972
u1.name = 'edchanged'
973
self._assert_cycle(u1)
974
self._assert_modified(u1)
976
self._assert_no_cycle(u1)
979
self._assert_cycle(u1)
980
self._assert_modified(u1)
982
@testing.requires.predictable_gc
983
def test_move_gc_session_persistent_dirty(self):
984
sess, u1 = self._persistent_fixture()
985
u1.name = 'edchanged'
986
self._assert_cycle(u1)
987
self._assert_modified(u1)
990
self._assert_cycle(u1)
993
self._assert_cycle(u1)
994
self._assert_modified(u1)
996
def test_persistent_dirty_to_expired(self):
997
sess, u1 = self._persistent_fixture()
998
u1.name = 'edchanged'
999
self._assert_cycle(u1)
1000
self._assert_modified(u1)
1002
self._assert_no_cycle(u1)
1003
self._assert_not_modified(u1)
1005
class WeakIdentityMapTest(_fixtures.FixtureTest):
1008
@testing.requires.predictable_gc
1009
def test_weakref(self):
1010
"""test the weak-referencing identity map, which strongly-
1011
references modified items."""
1013
users, User = self.tables.users, self.classes.User
1016
s = create_session()
1019
s.add(User(name='ed'))
1023
user = s.query(User).one()
1026
assert len(s.identity_map) == 0
1028
user = s.query(User).one()
1032
assert len(s.identity_map) == 1
1033
assert len(s.dirty) == 1
1034
assert None not in s.dirty
1038
assert not s.identity_map
1040
user = s.query(User).one()
1041
assert user.name == 'fred'
1042
assert s.identity_map
1044
@testing.requires.predictable_gc
1045
def test_weakref_pickled(self):
1046
users, User = self.tables.users, pickleable.User
1048
s = create_session()
1051
s.add(User(name='ed'))
1055
user = s.query(User).one()
1059
u2 = pickle.loads(pickle.dumps(user))
1067
assert len(s.identity_map) == 1
1068
assert len(s.dirty) == 1
1069
assert None not in s.dirty
1074
assert not s.identity_map
1076
@testing.requires.predictable_gc
1077
def test_weakref_with_cycles_o2m(self):
1078
Address, addresses, users, User = (self.classes.Address,
1079
self.tables.addresses,
1083
s = sessionmaker()()
1084
mapper(User, users, properties={
1085
"addresses": relationship(Address, backref="user")
1087
mapper(Address, addresses)
1088
s.add(User(name="ed", addresses=[Address(email_address="ed1")]))
1091
user = s.query(User).options(joinedload(User.addresses)).one()
1092
user.addresses[0].user # lazyload
1093
eq_(user, User(name="ed", addresses=[Address(email_address="ed1")]))
1097
assert len(s.identity_map) == 0
1099
user = s.query(User).options(joinedload(User.addresses)).one()
1100
user.addresses[0].email_address = 'ed2'
1101
user.addresses[0].user # lazyload
1104
assert len(s.identity_map) == 2
1107
user = s.query(User).options(joinedload(User.addresses)).one()
1108
eq_(user, User(name="ed", addresses=[Address(email_address="ed2")]))
1110
@testing.requires.predictable_gc
1111
def test_weakref_with_cycles_o2o(self):
1112
Address, addresses, users, User = (self.classes.Address,
1113
self.tables.addresses,
1117
s = sessionmaker()()
1118
mapper(User, users, properties={
1119
"address": relationship(Address, backref="user", uselist=False)
1121
mapper(Address, addresses)
1122
s.add(User(name="ed", address=Address(email_address="ed1")))
1125
user = s.query(User).options(joinedload(User.address)).one()
1127
eq_(user, User(name="ed", address=Address(email_address="ed1")))
1131
assert len(s.identity_map) == 0
1133
user = s.query(User).options(joinedload(User.address)).one()
1134
user.address.email_address = 'ed2'
1135
user.address.user # lazyload
1139
assert len(s.identity_map) == 2
1142
user = s.query(User).options(joinedload(User.address)).one()
1143
eq_(user, User(name="ed", address=Address(email_address="ed2")))
1145
def test_auto_detach_on_gc_session(self):
1146
users, User = self.tables.users, self.classes.User
1152
u1 = User(name='u1')
1156
# can't add u1 to Session,
1157
# already belongs to u2
1159
assert_raises_message(
1160
sa.exc.InvalidRequestError,
1161
r".*is already attached to session",
1165
# garbage collect sess
1169
# s2 lets it in now despite u1 having
1175
class StrongIdentityMapTest(_fixtures.FixtureTest):
1178
@testing.uses_deprecated()
1179
def test_strong_ref(self):
1180
users, User = self.tables.users, self.classes.User
1182
s = create_session(weak_identity_map=False)
1186
s.add(User(name='u1'))
1188
user = s.query(User).one()
1190
print s.identity_map
1192
assert len(s.identity_map) == 1
1194
user = s.query(User).one()
1195
assert not s.identity_map._modified
1197
assert s.identity_map._modified
1199
eq_(users.select().execute().fetchall(), [(user.id, 'u2')])
1201
@testing.uses_deprecated()
1202
@testing.fails_if(lambda: pypy, "pypy has a real GC")
1203
@testing.fails_on('+zxjdbc', 'http://www.sqlalchemy.org/trac/ticket/1473')
1204
def test_prune(self):
1205
users, User = self.tables.users, self.classes.User
1207
s = create_session(weak_identity_map=False)
1210
for o in [User(name='u%s' % x) for x in xrange(10)]:
1212
# o is still live after this loop...
1214
self.assert_(len(s.identity_map) == 0)
1215
self.assert_(s.prune() == 0)
1218
self.assert_(s.prune() == 9)
1219
self.assert_(len(s.identity_map) == 1)
1223
self.assert_(s.prune() == 1)
1224
self.assert_(len(s.identity_map) == 0)
1226
u = s.query(User).get(id)
1227
self.assert_(s.prune() == 0)
1228
self.assert_(len(s.identity_map) == 1)
1229
u.name = 'squiznart'
1231
self.assert_(s.prune() == 0)
1232
self.assert_(len(s.identity_map) == 1)
1234
self.assert_(s.prune() == 1)
1235
self.assert_(len(s.identity_map) == 0)
1237
s.add(User(name='x'))
1238
self.assert_(s.prune() == 0)
1239
self.assert_(len(s.identity_map) == 0)
1241
self.assert_(len(s.identity_map) == 1)
1242
self.assert_(s.prune() == 1)
1243
self.assert_(len(s.identity_map) == 0)
1245
u = s.query(User).get(id)
1248
self.assert_(s.prune() == 0)
1249
self.assert_(len(s.identity_map) == 1)
1251
self.assert_(s.prune() == 0)
1252
self.assert_(len(s.identity_map) == 0)
1023
1255
class IsModifiedTest(_fixtures.FixtureTest):
1024
1256
run_inserts = None
1381
1614
self.bind.commit()
1618
class FlushWarningsTest(fixtures.MappedTest):
1619
run_setup_mappers = 'each'
1622
def define_tables(cls, metadata):
1623
Table('user', metadata,
1624
Column('id', Integer, primary_key=True,
1625
test_needs_autoincrement=True),
1626
Column('name', String(20))
1629
Table('address', metadata,
1630
Column('id', Integer, primary_key=True,
1631
test_needs_autoincrement=True),
1632
Column('user_id', Integer, ForeignKey('user.id')),
1633
Column('email', String(20))
1637
def setup_classes(cls):
1638
class User(cls.Basic):
1640
class Address(cls.Basic):
1644
def setup_mappers(cls):
1645
user, User = cls.tables.user, cls.classes.User
1646
address, Address = cls.tables.address, cls.classes.Address
1647
mapper(User, user, properties={
1648
'addresses': relationship(Address, backref="user")
1650
mapper(Address, address)
1652
def test_o2m_cascade_add(self):
1653
Address = self.classes.Address
1654
def evt(mapper, conn, instance):
1655
instance.addresses.append(Address(email='x1'))
1656
self._test(evt, "collection append")
1658
def test_o2m_cascade_remove(self):
1659
def evt(mapper, conn, instance):
1660
del instance.addresses[0]
1661
self._test(evt, "collection remove")
1663
def test_m2o_cascade_add(self):
1664
User = self.classes.User
1665
def evt(mapper, conn, instance):
1666
instance.addresses[0].user = User(name='u2')
1667
self._test(evt, "related attribute set")
1669
def test_m2o_cascade_remove(self):
1670
def evt(mapper, conn, instance):
1671
a1 = instance.addresses[0]
1673
self._test(evt, "related attribute delete")
1675
def test_plain_add(self):
1676
Address = self.classes.Address
1677
def evt(mapper, conn, instance):
1678
object_session(instance).add(Address(email='x1'))
1679
self._test(evt, "Session.add\(\)")
1681
def test_plain_merge(self):
1682
Address = self.classes.Address
1683
def evt(mapper, conn, instance):
1684
object_session(instance).merge(Address(email='x1'))
1685
self._test(evt, "Session.merge\(\)")
1687
def test_plain_delete(self):
1688
Address = self.classes.Address
1689
def evt(mapper, conn, instance):
1690
object_session(instance).delete(Address(email='x1'))
1691
self._test(evt, "Session.delete\(\)")
1693
def _test(self, fn, method):
1694
User = self.classes.User
1695
Address = self.classes.Address
1698
event.listen(User, "after_insert", fn)
1700
u1 = User(name='u1', addresses=[Address(name='a1')])
1702
assert_raises_message(
1704
"Usage of the '%s'" % method,