* Use weakref's of DBCursor objects for the iterator cursors to avoid a
  memory leak that would've occurred for all iterators that were
  destroyed before having iterated until they raised StopIteration.

* Simplify some code.

* Add new test cases to check for the memleak and ensure that mixing
  iteration with modification of the values for existing keys works.
diff --git a/Lib/test/test_bsddb.py b/Lib/test/test_bsddb.py
index ff8c355..1ec4801 100755
--- a/Lib/test/test_bsddb.py
+++ b/Lib/test/test_bsddb.py
@@ -3,6 +3,7 @@
    Adapted to unittest format and expanded scope by Raymond Hettinger
 """
 import os, sys
+import copy
 import bsddb
 import dbhash # Just so we know it's imported
 import unittest
@@ -64,6 +65,56 @@
         self.assertSetEquals(d.itervalues(), f.itervalues())
         self.assertSetEquals(d.iteritems(), f.iteritems())
 
+    def test_iter_while_modifying_values(self):
+        if not hasattr(self.f, '__iter__'):
+            return
+
+        di = iter(self.d)
+        while 1:
+            try:
+                key = di.next()
+                self.d[key] = 'modified '+key
+            except StopIteration:
+                break
+
+        # it should behave the same as a dict.  modifying values
+        # of existing keys should not break iteration.  (adding
+        # or removing keys should)
+        fi = iter(self.f)
+        while 1:
+            try:
+                key = fi.next()
+                self.f[key] = 'modified '+key
+            except StopIteration:
+                break
+
+        self.test_mapping_iteration_methods()
+
+    def test_iteritems_while_modifying_values(self):
+        if not hasattr(self.f, 'iteritems'):
+            return
+
+        di = self.d.iteritems()
+        while 1:
+            try:
+                k, v = di.next()
+                self.d[k] = 'modified '+v
+            except StopIteration:
+                break
+
+        # it should behave the same as a dict.  modifying values
+        # of existing keys should not break iteration.  (adding
+        # or removing keys should)
+        fi = self.f.iteritems()
+        while 1:
+            try:
+                k, v = fi.next()
+                self.f[k] = 'modified '+v
+            except StopIteration:
+                break
+
+        self.test_mapping_iteration_methods()
+
     def test_first_next_looping(self):
         items = [self.f.first()]
         for i in xrange(1, len(self.f)):
@@ -111,15 +162,16 @@
         # the cursor's read lock will deadlock the write lock request..
 
         # test the iterator interface (if present)
-        if hasattr(self, 'iteritems'):
+        if hasattr(self.f, 'iteritems'):
             if debug: print "D"
-            k,v = self.f.iteritems()
+            i = self.f.iteritems()
+            k,v = i.next()
             if debug: print "E"
             self.f[k] = "please don't deadlock"
             if debug: print "F"
             while 1:
                 try:
-                    k,v = self.f.iteritems()
+                    k,v = i.next()
                 except StopIteration:
                     break
             if debug: print "F2"
@@ -144,6 +196,27 @@
         self.f[k] = "be gone with ye deadlocks"
         self.assert_(self.f[k], "be gone with ye deadlocks")
 
+    def test_for_cursor_memleak(self):
+        if not hasattr(self.f, 'iteritems'):
+            return
+
+        # do the bsddb._DBWithCursor _iter_mixin internals leak cursors?
+        nc1 = len(self.f._cursor_refs)
+        # create iterator
+        i = self.f.iteritems()
+        nc2 = len(self.f._cursor_refs)
+        # use the iterator (should run to the first yeild, creating the cursor)
+        k, v = i.next()
+        nc3 = len(self.f._cursor_refs)
+        # destroy the iterator; this should cause the weakref callback
+        # to remove the cursor object from self.f._cursor_refs
+        del i
+        nc4 = len(self.f._cursor_refs)
+
+        self.assertEqual(nc1, nc2)
+        self.assertEqual(nc1, nc4)
+        self.assert_(nc3 == nc1+1)
+
     def test_popitem(self):
         k, v = self.f.popitem()
         self.assert_(k in self.d)