\subsection{Database Objects \label{dbhash-objects}}
The database objects returned by \function{open()} provide the methods
-common to all the DBM-style databases. The following methods are
-available in addition to the standard methods.
+common to all the DBM-style databases and mapping objects. The following
+methods are available in addition to the standard methods.
\begin{methoddesc}[dbhash]{first}{}
- It's possible to loop over every key in the database using this method
- and the \method{next()} method. The traversal is ordered by
+ It's possible to loop over every key/value pair in the database using
+ this method and the \method{next()} method. The traversal is ordered by
the databases internal hash values, and won't be sorted by the key
values. This method returns the starting key.
\end{methoddesc}
\begin{methoddesc}[dbhash]{last}{}
- Return the last key in a database traversal. This may be used to
+ Return the last key/value pair in a database traversal. This may be used to
begin a reverse-order traversal; see \method{previous()}.
\end{methoddesc}
\begin{methoddesc}[dbhash]{next}{}
- Returns the key next key in a database traversal. The
+ Returns the key next key/value pair in a database traversal. The
following code prints every key in the database \code{db}, without
having to create a list in memory that contains them all:
\begin{verbatim}
print db.first()
-for i in xrange(1, len(d)):
+for i in xrange(1, len(db)):
print db.next()
\end{verbatim}
\end{methoddesc}
\begin{methoddesc}[dbhash]{previous}{}
- Returns the previous key in a forward-traversal of the database.
+ Returns the previous key/value pair in a forward-traversal of the database.
In conjunction with \method{last()}, this may be used to implement
a reverse-order traversal.
\end{methoddesc}
#! /usr/bin/env python
-"""Test script for the bsddb C module
- Roger E. Masse
+"""Test script for the bsddb C module by Roger E. Masse
+ Adapted to unittest format and expanded scope by Raymond Hettinger
"""
import os
import bsddb
import dbhash # Just so we know it's imported
-from test.test_support import verbose, verify, TESTFN
-
-def test(openmethod, what, ondisk=1):
-
- if verbose:
- print '\nTesting: ', what, (ondisk and "on disk" or "in memory")
-
- if ondisk:
- fname = TESTFN
- else:
- fname = None
- f = openmethod(fname, 'c')
- verify(f.keys() == [])
- if verbose:
- print 'creation...'
- f['0'] = ''
- f['a'] = 'Guido'
- f['b'] = 'van'
- f['c'] = 'Rossum'
- f['d'] = 'invented'
- f['f'] = 'Python'
- if verbose:
- print '%s %s %s' % (f['a'], f['b'], f['c'])
-
- if what == 'BTree' :
- if verbose:
- print 'key ordering...'
- f.set_location(f.first()[0])
- while 1:
- try:
- rec = f.next()
- except KeyError:
- if rec != f.last():
- print 'Error, last != last!'
- f.previous()
- break
- if verbose:
- print rec
- if not f.has_key('a'):
- print 'Error, missing key!'
-
- f.sync()
- f.close()
- if ondisk:
- # if we're using an in-memory only db, we can't reopen it
- # so finish here.
- if verbose:
- print 'modification...'
- f = openmethod(fname, 'w')
- f['d'] = 'discovered'
-
- if verbose:
- print 'access...'
- for key in f.keys():
- word = f[key]
- if verbose:
- print word
-
- f.close()
+import unittest
+from test import test_support
+from sets import Set
+
+class TestBSDDB(unittest.TestCase):
+
+ def setUp(self):
+ self.f = self.openmethod[0](self.fname, 'c')
+ self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
+ for k, v in self.d.iteritems():
+ self.f[k] = v
+
+ def tearDown(self):
+ self.f.sync()
+ self.f.close()
+ if self.fname is None:
+ return
try:
- os.remove(fname)
+ os.remove(self.fname)
except os.error:
pass
-types = [(bsddb.btopen, 'BTree'),
- (bsddb.hashopen, 'Hash Table'),
- (bsddb.btopen, 'BTree', 0),
- (bsddb.hashopen, 'Hash Table', 0),
- # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
- # appears broken... at least on
- # Solaris Intel - rmasse 1/97
- ]
-
-for type in types:
- test(*type)
+ def test_getitem(self):
+ for k, v in self.d.iteritems():
+ self.assertEqual(self.f[k], v)
+
+ def test_len(self):
+ self.assertEqual(len(self.f), len(self.d))
+
+ def test_change(self):
+ self.f['r'] = 'discovered'
+ self.assertEqual(self.f['r'], 'discovered')
+ self.assert_('r' in self.f.keys())
+ self.assert_('discovered' in self.f.values())
+
+ def test_close_and_reopen(self):
+ if self.fname is None:
+ # if we're using an in-memory only db, we can't reopen it
+ # so finish here.
+ return
+ self.f.close()
+ self.f = self.openmethod[0](self.fname, 'w')
+ for k, v in self.d.iteritems():
+ self.assertEqual(self.f[k], v)
+
+ def assertSetEquals(self, seqn1, seqn2):
+ self.assertEqual(Set(seqn1), Set(seqn2))
+
+ def test_mapping_iteration_methods(self):
+ f = self.f
+ d = self.d
+ self.assertSetEquals(d, f)
+ self.assertSetEquals(d.keys(), f.keys())
+ self.assertSetEquals(d.values(), f.values())
+ self.assertSetEquals(d.items(), f.items())
+ self.assertSetEquals(d.iterkeys(), f.iterkeys())
+ self.assertSetEquals(d.itervalues(), f.itervalues())
+ self.assertSetEquals(d.iteritems(), f.iteritems())
+
+ def test_first_next_looping(self):
+ items = [self.f.first()]
+ for i in xrange(1, len(self.f)):
+ items.append(self.f.next())
+ self.assertSetEquals(items, self.d.items())
+
+ def test_previous_last_looping(self):
+ items = [self.f.last()]
+ for i in xrange(1, len(self.f)):
+ items.append(self.f.previous())
+ self.assertSetEquals(items, self.d.items())
+
+ def test_set_location(self):
+ self.assertEqual(self.f.set_location('e'), ('e', self.d['e']))
+
+ def test_contains(self):
+ for k in self.d:
+ self.assert_(k in self.f)
+ self.assert_('not here' not in self.f)
+
+ def test_has_key(self):
+ for k in self.d:
+ self.assert_(self.f.has_key(k))
+ self.assert_(not self.f.has_key('not here'))
+
+ def test_clear(self):
+ self.f.clear()
+ self.assertEqual(len(self.f), 0)
+
+ def test_popitem(self):
+ k, v = self.f.popitem()
+ self.assert_(k in self.d)
+ self.assert_(v in self.d.values())
+ self.assert_(k not in self.f)
+ self.assertEqual(len(self.d)-1, len(self.f))
+
+ def test_pop(self):
+ k = 'w'
+ v = self.f.pop(k)
+ self.assertEqual(v, self.d[k])
+ self.assert_(k not in self.f)
+ self.assert_(v not in self.f.values())
+ self.assertEqual(len(self.d)-1, len(self.f))
+
+ def test_get(self):
+ self.assertEqual(self.f.get('NotHere'), None)
+ self.assertEqual(self.f.get('NotHere', 'Default'), 'Default')
+ self.assertEqual(self.f.get('q', 'Default'), self.d['q'])
+
+ def test_setdefault(self):
+ self.assertEqual(self.f.setdefault('new', 'dog'), 'dog')
+ self.assertEqual(self.f.setdefault('r', 'cat'), self.d['r'])
+
+ def test_update(self):
+ new = dict(y='life', u='of', i='brian')
+ self.f.update(new)
+ self.d.update(new)
+ for k, v in self.d.iteritems():
+ self.assertEqual(self.f[k], v)
+
+ def test_keyordering(self):
+ if self.openmethod[0] is not bsddb.btopen:
+ return
+ keys = self.d.keys()
+ keys.sort()
+ self.assertEqual(self.f.first()[0], keys[0])
+ self.assertEqual(self.f.next()[0], keys[1])
+ self.assertEqual(self.f.last()[0], keys[-1])
+ self.assertEqual(self.f.previous()[0], keys[-2])
+ self.assertEqual(list(self.f), keys)
+
+class TestBTree(TestBSDDB):
+ fname = test_support.TESTFN
+ openmethod = [bsddb.btopen]
+
+class TestBTree_InMemory(TestBSDDB):
+ fname = None
+ openmethod = [bsddb.btopen]
+
+class TestHashTable(TestBSDDB):
+ fname = test_support.TESTFN
+ openmethod = [bsddb.hashopen]
+
+class TestHashTable_InMemory(TestBSDDB):
+ fname = None
+ openmethod = [bsddb.hashopen]
+
+## # (bsddb.rnopen,'Record Numbers'), 'put' for RECNO for bsddb 1.85
+## # appears broken... at least on
+## # Solaris Intel - rmasse 1/97
+
+def test_main(verbose=None):
+ test_support.run_unittest(
+ TestBTree,
+ TestHashTable,
+ TestBTree_InMemory,
+ TestHashTable_InMemory,
+ )
+
+if __name__ == "__main__":
+ test_main(verbose=True)