From 7f5b6f4b33195ce9848bf396bbb52dab8d524587 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Sat, 8 Apr 2006 07:10:51 +0000 Subject: Fix bsddb.db.DBError derived exceptions so they can be unpickled. Also adds some backwards compatibility when compiling _bsddb.c on earlier python versions (needed for pybsddb). --- Lib/bsddb/test/test_all.py | 1 + Lib/bsddb/test/test_pickle.py | 75 +++++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 2 ++ Modules/_bsddb.c | 28 ++++++++++++---- 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 Lib/bsddb/test/test_pickle.py diff --git a/Lib/bsddb/test/test_all.py b/Lib/bsddb/test/test_all.py index 972cd06..abfaf47 100644 --- a/Lib/bsddb/test/test_all.py +++ b/Lib/bsddb/test/test_all.py @@ -65,6 +65,7 @@ def suite(): 'test_join', 'test_lock', 'test_misc', + 'test_pickle', 'test_queue', 'test_recno', 'test_thread', diff --git a/Lib/bsddb/test/test_pickle.py b/Lib/bsddb/test/test_pickle.py new file mode 100644 index 0000000..3916e5c --- /dev/null +++ b/Lib/bsddb/test/test_pickle.py @@ -0,0 +1,75 @@ + +import sys, os, string +import pickle +try: + import cPickle +except ImportError: + cPickle = None +import unittest +import glob + +try: + # For Pythons w/distutils pybsddb + from bsddb3 import db +except ImportError, e: + # For Python 2.3 + from bsddb import db + + +#---------------------------------------------------------------------- + +class pickleTestCase(unittest.TestCase): + """Verify that DBError can be pickled and unpickled""" + db_home = 'db_home' + db_name = 'test-dbobj.db' + + def setUp(self): + homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home') + self.homeDir = homeDir + try: os.mkdir(homeDir) + except os.error: pass + + def tearDown(self): + if hasattr(self, 'db'): + del self.db + if hasattr(self, 'env'): + del self.env + files = glob.glob(os.path.join(self.homeDir, '*')) + for file in files: + os.remove(file) + + def _base_test_pickle_DBError(self, pickle): + self.env = db.DBEnv() + self.env.open(self.homeDir, db.DB_CREATE | db.DB_INIT_MPOOL) + self.db = db.DB(self.env) + self.db.open(self.db_name, db.DB_HASH, db.DB_CREATE) + self.db.put('spam', 'eggs') + assert self.db['spam'] == 'eggs' + try: + self.db.put('spam', 'ham', flags=db.DB_NOOVERWRITE) + except db.DBError, egg: + pickledEgg = pickle.dumps(egg) + #print repr(pickledEgg) + rottenEgg = pickle.loads(pickledEgg) + if rottenEgg.args != egg.args or type(rottenEgg) != type(egg): + raise Exception, (rottenEgg, '!=', egg) + else: + raise Exception, "where's my DBError exception?!?" + + self.db.close() + self.env.close() + + def test01_pickle_DBError(self): + self._base_test_pickle_DBError(pickle=pickle) + + if cPickle: + def test02_cPickle_DBError(self): + self._base_test_pickle_DBError(pickle=cPickle) + +#---------------------------------------------------------------------- + +def test_suite(): + return unittest.makeSuite(pickleTestCase) + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/Misc/NEWS b/Misc/NEWS index bfac78c..266b6c9 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -15,6 +15,8 @@ Core and builtins Extension Modules ----------------- +- Fix bsddb.db.DBError derived exceptions so they can be unpickled. + Library ------- diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c index 9d0893e..7772046 100644 --- a/Modules/_bsddb.c +++ b/Modules/_bsddb.c @@ -101,6 +101,10 @@ static char *rcs_id = "$Id$"; +#if (PY_VERSION_HEX < 0x02050000) +#define Py_ssize_t int +#endif + #ifdef WITH_THREAD /* These are for when calling Python --> C */ @@ -4688,7 +4692,11 @@ static PyMethodDef DB_methods[] = { static PyMappingMethods DB_mapping = { +#if (PY_VERSION_HEX < 0x02050000) + (inquiry)DB_length, /*mp_length*/ +#else (lenfunc)DB_length, /*mp_length*/ +#endif (binaryfunc)DB_subscript, /*mp_subscript*/ (objobjargproc)DB_ass_sub, /*mp_ass_subscript*/ }; @@ -5385,9 +5393,21 @@ DL_EXPORT(void) init_bsddb(void) ADD_INT(d, DB_SET_TXN_TIMEOUT); #endif + /* The exception name must be correct for pickled exception * + * objects to unpickle properly. */ +#ifdef PYBSDDB_STANDALONE /* different value needed for standalone pybsddb */ +#define PYBSDDB_EXCEPTION_BASE "bsddb3.db." +#else +#define PYBSDDB_EXCEPTION_BASE "bsddb.db." +#endif + + /* All the rest of the exceptions derive only from DBError */ +#define MAKE_EX(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, DBError, NULL); \ + PyDict_SetItemString(d, #name, name) + /* The base exception class is DBError */ - DBError = PyErr_NewException("bsddb._db.DBError", NULL, NULL); - PyDict_SetItemString(d, "DBError", DBError); + DBError = NULL; /* used in MAKE_EX so that it derives from nothing */ + MAKE_EX(DBError); /* Some magic to make DBNotFoundError and DBKeyEmptyError derive * from both DBError and KeyError, since the API only supports @@ -5401,10 +5421,6 @@ DL_EXPORT(void) init_bsddb(void) PyDict_DelItemString(d, "KeyError"); - /* All the rest of the exceptions derive only from DBError */ -#define MAKE_EX(name) name = PyErr_NewException("bsddb._db." #name, DBError, NULL); \ - PyDict_SetItemString(d, #name, name) - #if !INCOMPLETE_IS_WARNING MAKE_EX(DBIncompleteError); #endif -- cgit v0.12