Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e4ed2de

Browse files
committed
pybsddb 4.3.1, adds support for DB.set_bt_compare database btree comparison
functions written in python. contributed by <[email protected]>
1 parent a43ece9 commit e4ed2de

4 files changed

Lines changed: 381 additions & 1 deletion

File tree

Lib/bsddb/dbobj.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ def rename(self, *args, **kwargs):
164164
return apply(self._cobj.rename, args, kwargs)
165165
def set_bt_minkey(self, *args, **kwargs):
166166
return apply(self._cobj.set_bt_minkey, args, kwargs)
167+
def set_bt_compare(self, *args, **kwargs):
168+
return apply(self._cobj.set_bt_compare, args, kwargs)
167169
def set_cachesize(self, *args, **kwargs):
168170
return apply(self._cobj.set_cachesize, args, kwargs)
169171
def set_flags(self, *args, **kwargs):

Lib/bsddb/test/test_all.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def suite():
5050
'test_associate',
5151
'test_basics',
5252
'test_compat',
53+
'test_compare',
5354
'test_dbobj',
5455
'test_dbshelve',
5556
'test_dbtables',

Lib/bsddb/test/test_compare.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
"""
2+
TestCases for python DB Btree key comparison function.
3+
"""
4+
5+
import sys, os
6+
import test_all
7+
8+
import unittest
9+
from bsddb3 import db
10+
11+
def lexical_cmp (db, left, right):
12+
return cmp (left, right)
13+
14+
def lowercase_cmp(db, left, right):
15+
return cmp (left.lower(), right.lower())
16+
17+
def make_reverse_comparator (cmp):
18+
def reverse (db, left, right, delegate=cmp):
19+
return - delegate (db, left, right)
20+
return reverse
21+
22+
_expected_lexical_test_data = ['', 'CCCP', 'a', 'aaa', 'b', 'c', 'cccce', 'ccccf']
23+
_expected_lowercase_test_data = ['', 'a', 'aaa', 'b', 'c', 'CC', 'cccce', 'ccccf', 'CCCP']
24+
25+
class ComparatorTests (unittest.TestCase):
26+
def comparator_test_helper (self, comparator, expected_data):
27+
data = expected_data[:]
28+
data.sort (lambda l, r, cmp=comparator: cmp (None, l, r))
29+
self.failUnless (data == expected_data,
30+
"comparator `%s' is not right: %s vs. %s"
31+
% (comparator, expected_data, data))
32+
def test_lexical_comparator (self):
33+
self.comparator_test_helper (lexical_cmp, _expected_lexical_test_data)
34+
def test_reverse_lexical_comparator (self):
35+
rev = _expected_lexical_test_data[:]
36+
rev.reverse ()
37+
self.comparator_test_helper (make_reverse_comparator (lexical_cmp),
38+
rev)
39+
def test_lowercase_comparator (self):
40+
self.comparator_test_helper (lowercase_cmp,
41+
_expected_lowercase_test_data)
42+
43+
class AbstractBtreeKeyCompareTestCase (unittest.TestCase):
44+
env = None
45+
db = None
46+
47+
def setUp (self):
48+
self.filename = self.__class__.__name__ + '.db'
49+
homeDir = os.path.join (os.path.dirname (sys.argv[0]), 'db_home')
50+
self.homeDir = homeDir
51+
try:
52+
os.mkdir (homeDir)
53+
except os.error:
54+
pass
55+
56+
env = db.DBEnv ()
57+
env.open (homeDir,
58+
db.DB_CREATE | db.DB_INIT_MPOOL
59+
| db.DB_INIT_LOCK | db.DB_THREAD)
60+
self.env = env
61+
62+
def tearDown (self):
63+
self.closeDB ()
64+
if self.env is not None:
65+
self.env.close ()
66+
self.env = None
67+
import glob
68+
map (os.remove, glob.glob (os.path.join (self.homeDir, '*')))
69+
70+
def addDataToDB (self, data):
71+
i = 0
72+
for item in data:
73+
self.db.put (item, str (i))
74+
i = i + 1
75+
76+
def createDB (self, key_comparator):
77+
self.db = db.DB (self.env)
78+
self.setupDB (key_comparator)
79+
self.db.open (self.filename, "test", db.DB_BTREE, db.DB_CREATE)
80+
81+
def setupDB (self, key_comparator):
82+
self.db.set_bt_compare (key_comparator)
83+
84+
def closeDB (self):
85+
if self.db is not None:
86+
self.db.close ()
87+
self.db = None
88+
89+
def startTest (self):
90+
pass
91+
92+
def finishTest (self, expected = None):
93+
if expected is not None:
94+
self.check_results (expected)
95+
self.closeDB ()
96+
97+
def check_results (self, expected):
98+
curs = self.db.cursor ()
99+
try:
100+
index = 0
101+
rec = curs.first ()
102+
while rec:
103+
key, ignore = rec
104+
self.failUnless (index < len (expected),
105+
"to many values returned from cursor")
106+
self.failUnless (expected[index] == key,
107+
"expected value `%s' at %d but got `%s'"
108+
% (expected[index], index, key))
109+
index = index + 1
110+
rec = curs.next ()
111+
self.failUnless (index == len (expected),
112+
"not enough values returned from cursor")
113+
finally:
114+
curs.close ()
115+
116+
class BtreeKeyCompareTestCase (AbstractBtreeKeyCompareTestCase):
117+
def runCompareTest (self, comparator, data):
118+
self.startTest ()
119+
self.createDB (comparator)
120+
self.addDataToDB (data)
121+
self.finishTest (data)
122+
123+
def test_lexical_ordering (self):
124+
self.runCompareTest (lexical_cmp, _expected_lexical_test_data)
125+
126+
def test_reverse_lexical_ordering (self):
127+
expected_rev_data = _expected_lexical_test_data[:]
128+
expected_rev_data.reverse ()
129+
self.runCompareTest (make_reverse_comparator (lexical_cmp),
130+
expected_rev_data)
131+
132+
def test_compare_function_useless (self):
133+
self.startTest ()
134+
def socialist_comparator (db, l, r):
135+
return 0
136+
self.createDB (socialist_comparator)
137+
self.addDataToDB (['b', 'a', 'd'])
138+
# all things being equal the first key will be the only key
139+
# in the database... (with the last key's value fwiw)
140+
self.finishTest (['b'])
141+
142+
143+
class BtreeExceptionsTestCase (AbstractBtreeKeyCompareTestCase):
144+
def test_raises_non_callable (self):
145+
self.startTest ()
146+
self.assertRaises (TypeError, self.createDB, 'abc')
147+
self.assertRaises (TypeError, self.createDB, None)
148+
self.finishTest ()
149+
150+
def test_set_bt_compare_with_function (self):
151+
self.startTest ()
152+
self.createDB (lexical_cmp)
153+
self.finishTest ()
154+
155+
def check_results (self, results):
156+
pass
157+
158+
def test_compare_function_incorrect (self):
159+
self.startTest ()
160+
def bad_comparator (db, l, r):
161+
return 1
162+
# verify that set_bt_compare checks that comparator(db, '', '') == 0
163+
self.assertRaises (TypeError, self.createDB, bad_comparator)
164+
self.finishTest ()
165+
166+
def test_compare_function_exception (self):
167+
self.startTest ()
168+
def bad_comparator (db, l, r):
169+
if l == r:
170+
# pass the set_bt_compare test
171+
return 0
172+
raise RuntimeError, "i'm a naughty comparison function"
173+
self.createDB (bad_comparator)
174+
print "\n*** this test should print 2 uncatchable tracebacks ***"
175+
self.addDataToDB (['a', 'b', 'c']) # this should raise, but...
176+
self.finishTest ()
177+
178+
def test_compare_function_bad_return (self):
179+
self.startTest ()
180+
def bad_comparator (db, l, r):
181+
if l == r:
182+
# pass the set_bt_compare test
183+
return 0
184+
return l
185+
self.createDB (bad_comparator)
186+
print "\n*** this test should print 2 errors about returning an int ***"
187+
self.addDataToDB (['a', 'b', 'c']) # this should raise, but...
188+
self.finishTest ()
189+
190+
191+
def test_cannot_assign_twice (self):
192+
193+
def my_compare (db, a, b):
194+
return 0
195+
196+
self.startTest ()
197+
self.createDB (my_compare)
198+
try:
199+
self.db.set_bt_compare (my_compare)
200+
assert False, "this set should fail"
201+
202+
except RuntimeError, msg:
203+
pass
204+
205+
def test_suite ():
206+
res = unittest.TestSuite ()
207+
208+
res.addTest (unittest.makeSuite (ComparatorTests))
209+
if db.version () >= (3, 3, 11):
210+
res.addTest (unittest.makeSuite (BtreeExceptionsTestCase))
211+
res.addTest (unittest.makeSuite (BtreeKeyCompareTestCase))
212+
return res
213+
214+
if __name__ == '__main__':
215+
unittest.main (defaultTest = 'suite')

0 commit comments

Comments
 (0)