From: Raymond Hettinger Date: Tue, 16 Sep 2003 21:42:13 +0000 (+0000) Subject: Fix documentation bugs. X-Git-Tag: v2.3.1~45 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4737992e8c894e586dd31cd41f2a936e499bca27;p=thirdparty%2FPython%2Fcpython.git Fix documentation bugs. Add support for iterators and other mapping methods. Convert tests to unittest format and expand their coverage. --- diff --git a/Doc/lib/libbsddb.tex b/Doc/lib/libbsddb.tex index 7fb8f76e01b4..8c6b39284669 100644 --- a/Doc/lib/libbsddb.tex +++ b/Doc/lib/libbsddb.tex @@ -100,8 +100,10 @@ systems which ship with the old Berkeley DB 1.85 database library. The \subsection{Hash, BTree and Record Objects \label{bsddb-objects}} -Once instantiated, hash, btree and record objects support the following -methods: +Once instantiated, hash, btree and record objects support +the same methods as dictionaries. In addition, they support +the methods listed below. +\versionchanged[Added mapping methods]{2.3.1} \begin{methoddesc}{close}{} Close the underlying file. The object can no longer be accessed. Since @@ -177,6 +179,20 @@ Example: ('2', '4') >>> db.previous() ('1', '1') +>>> for k, v in db.iteritems(): +... print k, v +0 0 +1 1 +2 4 +3 9 +4 16 +5 25 +6 36 +7 49 +8 64 +9 81 +>>> 8 in db +True >>> db.sync() 0 \end{verbatim} diff --git a/Doc/lib/libdbhash.tex b/Doc/lib/libdbhash.tex index 00a6d080bfde..f5f98eae19c7 100644 --- a/Doc/lib/libdbhash.tex +++ b/Doc/lib/libdbhash.tex @@ -51,35 +51,35 @@ This module provides an exception and a function: \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} diff --git a/Lib/bsddb/__init__.py b/Lib/bsddb/__init__.py index 1ec6adc195f2..2910236b3d74 100644 --- a/Lib/bsddb/__init__.py +++ b/Lib/bsddb/__init__.py @@ -52,8 +52,9 @@ error = db.DBError # So bsddb.error will mean something... #---------------------------------------------------------------------- +import UserDict -class _DBWithCursor: +class _DBWithCursor(UserDict.DictMixin): """ A simple wrapper around DB that makes it look like the bsddbobject in the old module. It uses a cursor as needed to provide DB traversal. @@ -144,6 +145,23 @@ class _DBWithCursor: self._checkOpen() return self.db.sync() + def __iter__(self): + try: + yield self.first()[0] + next = self.next + while 1: + yield next()[0] + except _bsddb.DBNotFoundError: + return + + def iteritems(self): + try: + yield self.first() + next = self.next + while 1: + yield next() + except _bsddb.DBNotFoundError: + return #---------------------------------------------------------------------- # Compatibility object factory functions diff --git a/Lib/test/test_bsddb.py b/Lib/test/test_bsddb.py index aa58ef8ef7f6..73a2d966057f 100755 --- a/Lib/test/test_bsddb.py +++ b/Lib/test/test_bsddb.py @@ -1,82 +1,167 @@ #! /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) diff --git a/Misc/NEWS b/Misc/NEWS index 79bd3ffff132..b25698c6fd7d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,9 @@ Extension modules Library ------- +- The bsddb module and dbhash module now support the iterator and + mapping protocols. + - Bug #711632: Reset all state members in HTMLParser.reset. - Bug #792649: logging.ConfigStreamHandler had an uninitialized variable