s.commit()
-# these tests simply cannot run reliably on github actions machines.
-# even trying ten times, they sometimes can't proceed.
-@testing.add_to_marker.gc_intensive
class WeakIdentityMapTest(_fixtures.FixtureTest):
run_inserts = None
- def run_up_to_n_times(self, fn, times):
- error = None
- for _ in range(times):
- try:
- fn()
- except Exception as err:
- error = err
- with testing.db.begin() as conn:
- conn.execute(self.tables.addresses.delete())
- conn.execute(self.tables.users.delete())
- continue
- else:
- break
- else:
- if error:
- raise error
-
- @testing.requires.predictable_gc
def test_weakref(self):
"""test the weak-referencing identity map, which strongly-
references modified items."""
users, User = self.tables.users, self.classes.User
self.mapper_registry.map_imperatively(User, users)
- def go():
- with Session(testing.db) as s:
- gc_collect()
+ with Session(testing.db) as s:
+ gc_collect()
- s.add(User(name="ed"))
- s.flush()
- assert not s.dirty
+ s.add(User(name="ed"))
+ s.flush()
+ assert not s.dirty
- user = s.query(User).one()
+ user = s.query(User).one()
- # heisenberg the GC a little bit, since #7823 caused a lot more
- # GC when mappings are set up, larger test suite started
- # failing on this being gc'ed
- user_is = user._sa_instance_state
- del user
- gc_collect()
- gc_collect()
- gc_collect()
- assert user_is.obj() is None
+ user_is = user._sa_instance_state
+ del user
+ user_is._force_dereference()
- assert len(s.identity_map) == 0
+ assert len(s.identity_map) == 0
- user = s.query(User).one()
- user.name = "fred"
- del user
- gc_collect()
- assert len(s.identity_map) == 1
- assert len(s.dirty) == 1
- assert None not in s.dirty
- s.flush()
- gc_collect()
- assert not s.dirty
- assert not s.identity_map
+ user = s.query(User).one()
+ user_is = user._sa_instance_state
+ user.name = "fred"
- user = s.query(User).one()
- assert user.name == "fred"
- assert s.identity_map
+ del user
+ gc_collect()
- self.run_up_to_n_times(go, 10)
+ # object was not gc'ed
+ assert user_is.obj()
+
+ assert len(s.identity_map) == 1
+ assert len(s.dirty) == 1
+ assert None not in s.dirty
+ s.flush()
+ gc_collect()
+ user_is._force_dereference()
+
+ assert not s.dirty
+ assert not s.identity_map
+
+ user = s.query(User).one()
+ assert user.name == "fred"
+ assert s.identity_map
- @testing.requires.predictable_gc
def test_weakref_pickled(self):
users, User = self.tables.users, pickleable.User
self.mapper_registry.map_imperatively(User, users)
- def go():
- with Session(testing.db) as s:
- gc_collect()
+ with Session(testing.db) as s:
+ gc_collect()
- s.add(User(name="ed"))
- s.flush()
- assert not s.dirty
+ s.add(User(name="ed"))
+ s.flush()
+ assert not s.dirty
- user = s.query(User).one()
- user.name = "fred"
- s.expunge(user)
+ user = s.query(User).one()
+ user.name = "fred"
+ s.expunge(user)
- u2 = pickle.loads(pickle.dumps(user))
+ u2 = pickle.loads(pickle.dumps(user))
- del user
- s.add(u2)
+ uis = user._sa_instance_state
+ u2is = u2._sa_instance_state
- del u2
- gc_collect()
+ del user
+ uis._force_dereference()
- assert len(s.identity_map) == 1
- assert len(s.dirty) == 1
- assert None not in s.dirty
- s.flush()
- gc_collect()
- assert not s.dirty
+ s.add(u2)
- assert not s.identity_map
+ del u2
- self.run_up_to_n_times(go, 10)
+ # was not gced
+ assert u2is.obj() is not None
+ assert len(s.identity_map) == 1
+ assert len(s.dirty) == 1
+ assert None not in s.dirty
+ s.flush()
+
+ gc_collect()
+ u2is._force_dereference()
+
+ assert not s.dirty
+
+ assert not s.identity_map
- @testing.requires.predictable_gc
def test_weakref_with_cycles_o2m(self):
Address, addresses, users, User = (
self.classes.Address,
properties={"addresses": relationship(Address, backref="user")},
)
self.mapper_registry.map_imperatively(Address, addresses)
- gc_collect()
- def go():
- with Session(testing.db) as s:
- s.add(
- User(name="ed", addresses=[Address(email_address="ed1")])
- )
- s.commit()
+ with Session(testing.db) as s:
+ s.add(User(name="ed", addresses=[Address(email_address="ed1")]))
+ s.commit()
- user = s.query(User).options(joinedload(User.addresses)).one()
- user.addresses[0].user # lazyload
- eq_(
- user,
- User(name="ed", addresses=[Address(email_address="ed1")]),
- )
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ user.addresses[0].user # lazyload
+ eq_(
+ user,
+ User(name="ed", addresses=[Address(email_address="ed1")]),
+ )
- del user
- gc_collect()
- assert len(s.identity_map) == 0
+ del user
+ gc_collect()
+ assert len(s.identity_map) == 0
- user = s.query(User).options(joinedload(User.addresses)).one()
- user.addresses[0].email_address = "ed2"
- user.addresses[0].user # lazyload
- del user
- gc_collect()
- assert len(s.identity_map) == 2
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ uis = user._sa_instance_state
- s.commit()
- user = s.query(User).options(joinedload(User.addresses)).one()
- eq_(
- user,
- User(name="ed", addresses=[Address(email_address="ed2")]),
- )
+ user.addresses[0].email_address = "ed2"
+ user.addresses[0].user # lazyload
+ del user
+ gc_collect()
- self.run_up_to_n_times(go, 10)
+ # was not GC'ed
+ assert uis.obj() is not None
+
+ assert len(s.identity_map) == 2
+
+ s.commit()
+ user = s.query(User).options(joinedload(User.addresses)).one()
+ eq_(
+ user,
+ User(name="ed", addresses=[Address(email_address="ed2")]),
+ )
- @testing.requires.predictable_gc
def test_weakref_with_cycles_o2o(self):
Address, addresses, users, User = (
self.classes.Address,
},
)
self.mapper_registry.map_imperatively(Address, addresses)
- gc_collect()
s.add(User(name="ed", address=Address(email_address="ed1")))
s.commit()
user.address.user
eq_(user, User(name="ed", address=Address(email_address="ed1")))
+ uis = user._sa_instance_state
+ ais = user.address._sa_instance_state
del user
gc_collect()
+
+ # in case gc collect didn't work, force a dereference
+ uis._force_dereference()
+ ais._force_dereference()
+
+ # identity map is cleaned out
assert len(s.identity_map) == 0
user = s.query(User).options(joinedload(User.address)).one()
+ uis = user._sa_instance_state
user.address.email_address = "ed2"
user.address.user # lazyload
del user
gc_collect()
+
+ # was not gc'ed
+ assert uis.obj() is not None
+
assert len(s.identity_map) == 2
s.commit()
self._assert_not_hasparent(a1)
- @testing.add_to_marker.gc_intensive
- @testing.requires.predictable_gc
def test_stale_state_positive_gc(self):
User = self.classes.User
s, u1, a1 = self._fixture()
s.expunge(u1)
- del u1
- gc_collect()
+
+ u1_is = u1._sa_instance_state
+ # act as though GC happened
+ u1_is._force_dereference()
u1 = s.query(User).first()
u1.addresses.remove(a1)
self._assert_not_hasparent(a1)
- @testing.add_to_marker.gc_intensive
@testing.requires.updateable_autoincrement_pks
- @testing.requires.predictable_gc
def test_stale_state_positive_pk_change(self):
"""Illustrate that we can't easily link a
stale state to a fresh one if the fresh one has
s._expunge_states([attributes.instance_state(u1)])
- del u1
- gc_collect()
-
u1 = s.query(User).first()
# primary key change. now we
self._assert_not_hasparent(a1)
- @testing.add_to_marker.gc_intensive
- @testing.requires.predictable_gc
def test_stale_state_negative_child_expired(self):
"""illustrate the current behavior of
expiration on the child.
u1.addresses.remove(a1)
u2_is = u2._sa_instance_state
- del u2
- for i in range(5):
- gc_collect()
- # heisenberg the GC a little bit, since #7823 caused a lot more
- # GC when mappings are set up, larger test suite started failing
- # on this being gc'ed
- o = u2_is.obj()
- assert o is None
+ # act as though GC happened
+ u2_is._force_dereference()
# controversy here. The action is
# to expire one object, not the other, and remove;
self._assert_not_hasparent(a1)
# self._assert_hasparent(a1)
- @testing.add_to_marker.gc_intensive
- @testing.requires.predictable_gc
def test_stale_state_negative(self):
User = self.classes.User
s, u1, a1 = self._fixture()
s._expunge_states([attributes.instance_state(u2)])
u2_is = u2._sa_instance_state
- del u2
-
- for i in range(5):
- gc_collect()
- # heisenberg the GC a little bit, since #7823 caused a lot more
- # GC when mappings are set up, larger test suite started failing
- # on this being gc'ed
- o = u2_is.obj()
- assert o is None
+
+ u2_is._force_dereference()
assert_raises_message(
orm_exc.StaleDataError,