diff --git a/Lib/bsddb/dbshelve.py b/Lib/bsddb/dbshelve.py index d341ab79109..82e914d05a4 100644 --- a/Lib/bsddb/dbshelve.py +++ b/Lib/bsddb/dbshelve.py @@ -75,6 +75,9 @@ def open(filename, flags=db.DB_CREATE, mode=0660, filetype=db.DB_HASH, #--------------------------------------------------------------------------- +class DBShelveError(db.DBError): pass + + class DBShelf(DictMixin): """A shelf to hold pickled objects, built upon a bsddb DB object. It automatically pickles/unpickles data objects going to/from the DB. @@ -150,10 +153,10 @@ class DBShelf(DictMixin): return self.db.append(data, txn) def append(self, value, txn=None): - if self.get_type() != db.DB_RECNO: + if self.get_type() == db.DB_RECNO: self.append = self.__append return self.append(value, txn=txn) - raise db.DBError, "append() only supported when dbshelve opened with filetype=dbshelve.db.DB_RECNO" + raise DBShelveError, "append() only supported when dbshelve opened with filetype=dbshelve.db.DB_RECNO" def associate(self, secondaryDB, callback, flags=0): diff --git a/Lib/bsddb/test/test_dbshelve.py b/Lib/bsddb/test/test_dbshelve.py index 722ee5b407d..e3b8997cfd0 100644 --- a/Lib/bsddb/test/test_dbshelve.py +++ b/Lib/bsddb/test/test_dbshelve.py @@ -41,17 +41,22 @@ class DBShelveTestCase(unittest.TestCase): except os.error: pass + def mk(self, key): + """Turn key into an appropriate key type for this db""" + # override in child class for RECNO + return key + def populateDB(self, d): for x in string.letters: - d['S' + x] = 10 * x # add a string - d['I' + x] = ord(x) # add an integer - d['L' + x] = [x] * 10 # add a list + d[self.mk('S' + x)] = 10 * x # add a string + d[self.mk('I' + x)] = ord(x) # add an integer + d[self.mk('L' + x)] = [x] * 10 # add a list inst = DataClass() # add an instance inst.S = 10 * x inst.I = ord(x) inst.L = [x] * 10 - d['O' + x] = inst + d[self.mk('O' + x)] = inst # overridable in derived classes to affect how the shelf is created/opened @@ -85,14 +90,14 @@ class DBShelveTestCase(unittest.TestCase): print "keys:", k print "stats:", s - assert 0 == d.has_key('bad key') - assert 1 == d.has_key('IA') - assert 1 == d.has_key('OA') + assert 0 == d.has_key(self.mk('bad key')) + assert 1 == d.has_key(self.mk('IA')) + assert 1 == d.has_key(self.mk('OA')) - d.delete('IA') - del d['OA'] - assert 0 == d.has_key('IA') - assert 0 == d.has_key('OA') + d.delete(self.mk('IA')) + del d[self.mk('OA')] + assert 0 == d.has_key(self.mk('IA')) + assert 0 == d.has_key(self.mk('OA')) assert len(d) == l-2 values = [] @@ -115,18 +120,18 @@ class DBShelveTestCase(unittest.TestCase): for key, value in items: self.checkrec(key, value) - assert d.get('bad key') == None - assert d.get('bad key', None) == None - assert d.get('bad key', 'a string') == 'a string' - assert d.get('bad key', [1, 2, 3]) == [1, 2, 3] + assert d.get(self.mk('bad key')) == None + assert d.get(self.mk('bad key'), None) == None + assert d.get(self.mk('bad key'), 'a string') == 'a string' + assert d.get(self.mk('bad key'), [1, 2, 3]) == [1, 2, 3] d.set_get_returns_none(0) - self.assertRaises(db.DBNotFoundError, d.get, 'bad key') + self.assertRaises(db.DBNotFoundError, d.get, self.mk('bad key')) d.set_get_returns_none(1) - d.put('new key', 'new data') - assert d.get('new key') == 'new data' - assert d['new key'] == 'new data' + d.put(self.mk('new key'), 'new data') + assert d.get(self.mk('new key')) == 'new data' + assert d[self.mk('new key')] == 'new data' @@ -165,14 +170,24 @@ class DBShelveTestCase(unittest.TestCase): assert count == len(d) - c.set('SS') + c.set(self.mk('SS')) key, value = c.current() self.checkrec(key, value) del c + def test03_append(self): + # NOTE: this is overridden in RECNO subclass, don't change its name. + if verbose: + print '\n', '-=' * 30 + print "Running %s.test03_append..." % self.__class__.__name__ + + self.assertRaises(dbshelve.DBShelveError, + self.d.append, 'unit test was here') + def checkrec(self, key, value): + # override this in a subclass if the key type is different x = key[1] if key[0] == 'S': assert type(value) == StringType @@ -281,7 +296,43 @@ class EnvThreadHashShelveTestCase(BasicEnvShelveTestCase): #---------------------------------------------------------------------- -# TODO: Add test cases for a DBShelf in a RECNO DB. +# test cases for a DBShelf in a RECNO DB. + +class RecNoShelveTestCase(BasicShelveTestCase): + dbtype = db.DB_RECNO + dbflags = db.DB_CREATE + + def setUp(self): + BasicShelveTestCase.setUp(self) + + # pool to assign integer key values out of + self.key_pool = list(range(1, 5000)) + self.key_map = {} # map string keys to the number we gave them + self.intkey_map = {} # reverse map of above + + def mk(self, key): + if key not in self.key_map: + self.key_map[key] = self.key_pool.pop(0) + self.intkey_map[self.key_map[key]] = key + return self.key_map[key] + + def checkrec(self, intkey, value): + key = self.intkey_map[intkey] + BasicShelveTestCase.checkrec(self, key, value) + + def test03_append(self): + if verbose: + print '\n', '-=' * 30 + print "Running %s.test03_append..." % self.__class__.__name__ + + self.d[1] = 'spam' + self.d[5] = 'eggs' + self.assertEqual(6, self.d.append('spam')) + self.assertEqual(7, self.d.append('baked beans')) + self.assertEqual('spam', self.d.get(6)) + self.assertEqual('spam', self.d.get(1)) + self.assertEqual('baked beans', self.d.get(7)) + self.assertEqual('eggs', self.d.get(5)) #---------------------------------------------------------------------- @@ -298,6 +349,7 @@ def test_suite(): suite.addTest(unittest.makeSuite(EnvHashShelveTestCase)) suite.addTest(unittest.makeSuite(EnvThreadBTreeShelveTestCase)) suite.addTest(unittest.makeSuite(EnvThreadHashShelveTestCase)) + suite.addTest(unittest.makeSuite(RecNoShelveTestCase)) return suite diff --git a/Misc/NEWS b/Misc/NEWS index 8642f2a23f6..2d9af12b3cb 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -115,6 +115,9 @@ Extension Modules - Bug #1721309: prevent bsddb module from freeing random memory. +- Bug #1233: fix bsddb.dbshelve.DBShelf append method to work as + intended for RECNO databases. + - Bug #1726026: Correct the field names of WIN32_FIND_DATAA and WIN32_FIND_DATAW structures in the ctypes.wintypes module.