[Python-checkins] python/dist/src/Lib/test test_weakref.py,1.17.4.1,1.17.4.2
bwarsaw@users.sourceforge.net
bwarsaw@users.sourceforge.net
Wed, 28 May 2003 16:03:32 -0700
Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1:/tmp/cvs-serv30946/Lib/test
Modified Files:
Tag: release22-maint
test_weakref.py
Log Message:
The backport gets Fred's seal of approval:
SF 742860: WeakKeyDictionary __delitem__ uses iterkeys
Someone review this, please! Final releases are getting close, Fred
(the weakref guy) won't be around until Tuesday, and the pre-patch
code can indeed raise spurious RuntimeErrors in the presence of
threads or mutating comparison functions.
See the bug report for my confusions: I can't see any reason for why
__delitem__ iterated over the keys. The new one-liner implementation
is much faster, can't raise RuntimeError, and should be better-behaved
in all respects wrt threads.
New tests test_weak_keyed_bad_delitem and
test_weak_keyed_cascading_deletes fail before this patch.
Backported the tests and the patch.
Index: test_weakref.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_weakref.py,v
retrieving revision 1.17.4.1
retrieving revision 1.17.4.2
diff -C2 -d -r1.17.4.1 -r1.17.4.2
*** test_weakref.py 23 Aug 2002 16:29:27 -0000 1.17.4.1
--- test_weakref.py 28 May 2003 23:03:30 -0000 1.17.4.2
***************
*** 503,506 ****
--- 503,564 ----
self.assert_(d.items() == [('something else', o2)])
+ def test_weak_keyed_bad_delitem(self):
+ d = weakref.WeakKeyDictionary()
+ o = Object('1')
+ # An attempt to delete an object that isn't there should raise
+ # KeyError. It didn't before 2.3.
+ self.assertRaises(KeyError, d.__delitem__, o)
+ self.assertRaises(KeyError, d.__getitem__, o)
+
+ # If a key isn't of a weakly referencable type, __getitem__ and
+ # __setitem__ raise TypeError. __delitem__ should too.
+ self.assertRaises(TypeError, d.__delitem__, 13)
+ self.assertRaises(TypeError, d.__getitem__, 13)
+ self.assertRaises(TypeError, d.__setitem__, 13, 13)
+
+ def test_weak_keyed_cascading_deletes(self):
+ # SF bug 742860. For some reason, before 2.3 __delitem__ iterated
+ # over the keys via self.data.iterkeys(). If things vanished from
+ # the dict during this (or got added), that caused a RuntimeError.
+
+ d = weakref.WeakKeyDictionary()
+ mutate = False
+
+ class C(object):
+ def __init__(self, i):
+ self.value = i
+ def __hash__(self):
+ return hash(self.value)
+ def __eq__(self, other):
+ if mutate:
+ # Side effect that mutates the dict, by removing the
+ # last strong reference to a key.
+ del objs[-1]
+ return self.value == other.value
+
+ objs = [C(i) for i in range(4)]
+ for o in objs:
+ d[o] = o.value
+ del o # now the only strong references to keys are in objs
+ # Find the order in which iterkeys sees the keys.
+ objs = d.keys()
+ # Reverse it, so that the iteration implementation of __delitem__
+ # has to keep looping to find the first object we delete.
+ objs.reverse()
+
+ # Turn on mutation in C.__eq__. The first time thru the loop,
+ # under the iterkeys() business the first comparison will delete
+ # the last item iterkeys() would see, and that causes a
+ # RuntimeError: dictionary changed size during iteration
+ # when the iterkeys() loop goes around to try comparing the next
+ # key. After this was fixed, it just deletes the last object *our*
+ # "for o in obj" loop would have gotten to.
+ mutate = True
+ count = 0
+ for o in objs:
+ count += 1
+ del d[o]
+ self.assertEqual(len(d), 0)
+ self.assertEqual(count, 2)
def test_main():