[Python-3000-checkins] r56754 - in python/branches/py3k-struni: Doc/lib/libbsddb.tex Lib/bsddb/__init__.py Lib/test/test_bsddb.py Modules/_bsddb.c

martin.v.loewis python-3000-checkins at python.org
Sun Aug 5 17:39:16 CEST 2007


Author: martin.v.loewis
Date: Sun Aug  5 17:39:16 2007
New Revision: 56754

Modified:
   python/branches/py3k-struni/Doc/lib/libbsddb.tex
   python/branches/py3k-struni/Lib/bsddb/__init__.py
   python/branches/py3k-struni/Lib/test/test_bsddb.py
   python/branches/py3k-struni/Modules/_bsddb.c
Log:
Make bsddb use bytes as keys and values. Add StringKeys
and StringValues classes. Fix test suite.


Modified: python/branches/py3k-struni/Doc/lib/libbsddb.tex
==============================================================================
--- python/branches/py3k-struni/Doc/lib/libbsddb.tex	(original)
+++ python/branches/py3k-struni/Doc/lib/libbsddb.tex	Sun Aug  5 17:39:16 2007
@@ -93,6 +93,17 @@
 interpretation.
 \end{funcdesc}
 
+\begin{classdesc}{StringKeys}{db}
+  Wrapper class around a DB object that supports string keys
+  (rather than bytes). All keys are encoded as UTF-8, then passed
+  to the underlying object. \versionadded{3.0}
+\end{classdesc}
+
+\begin{classdesc}{StringValues}{db}
+  Wrapper class around a DB object that supports string values
+  (rather than bytes). All values are encoded as UTF-8, then passed
+  to the underlying object. \versionadded{3.0}
+\end{classdesc}
 
 \begin{seealso}
   \seemodule{dbhash}{DBM-style interface to the \module{bsddb}}

Modified: python/branches/py3k-struni/Lib/bsddb/__init__.py
==============================================================================
--- python/branches/py3k-struni/Lib/bsddb/__init__.py	(original)
+++ python/branches/py3k-struni/Lib/bsddb/__init__.py	Sun Aug  5 17:39:16 2007
@@ -64,15 +64,9 @@
 
 #----------------------------------------------------------------------
 
-import sys, os
+import sys, os, UserDict
+from weakref import ref
 
-# for backwards compatibility with python versions older than 2.3, the
-# iterator interface is dynamically defined and added using a mixin
-# class.  old python can't tokenize it due to the yield keyword.
-if sys.version >= '2.3':
-    import UserDict
-    from weakref import ref
-    exec("""
 class _iter_mixin(UserDict.DictMixin):
     def _make_iter_cursor(self):
         cur = _DeadlockWrap(self.db.cursor)
@@ -145,10 +139,6 @@
         except _bsddb.DBCursorClosedError:
             # the database was modified during iteration.  abort.
             return
-""")
-else:
-    class _iter_mixin: pass
-
 
 class _DBWithCursor(_iter_mixin):
     """
@@ -290,6 +280,138 @@
         self._checkOpen()
         return _DeadlockWrap(self.db.sync)
 
+class _ExposedProperties:
+    @property
+    def _cursor_refs(self):
+        return self.db._cursor_refs
+
+class StringKeys(UserDict.DictMixin, _ExposedProperties):
+    """Wrapper around DB object that automatically encodes
+    all keys as UTF-8; the keys must be strings."""
+
+    def __init__(self, db):
+        self.db = db
+
+    def __len__(self):
+        return len(self.db)
+
+    def __getitem__(self, key):
+        return self.db[key.encode("utf-8")]
+
+    def __setitem__(self, key, value):
+        self.db[key.encode("utf-8")] = value
+
+    def __delitem__(self, key):
+        del self.db[key.encode("utf-8")]
+
+    def __iter__(self):
+        for k in self.db:
+            yield k.decode("utf-8")
+
+    def close(self):
+        self.db.close()
+
+    def keys(self):
+        for k in self.db.keys():
+            yield k.decode("utf-8")
+
+    def has_key(self, key):
+        return self.db.has_key(key.encode("utf-8"))
+
+    __contains__ = has_key
+
+    def values(self):
+        return self.db.values()
+
+    def items(self):
+        for k,v in self.db.items():
+            yield k.decode("utf-8"), v
+
+    def set_location(self, key):
+        return self.db.set_location(key.encode("utf-8"))
+
+    def next(self):
+        key, value = self.db.next()
+        return key.decode("utf-8"), value
+
+    def previous(self):
+        key, value = self.db.previous()
+        return key.decode("utf-8"), value
+
+    def first(self):
+        key, value = self.db.first()
+        return key.decode("utf-8"), value
+
+    def last(self):
+        key, value = self.db.last()
+        return key.decode("utf-8"), value
+
+    def sync(self):
+        return self.db.sync()
+
+class StringValues(UserDict.DictMixin, _ExposedProperties):
+    """Wrapper around DB object that automatically encodes
+    all keys as UTF-8; the keys must be strings."""
+
+    def __init__(self, db):
+        self.db = db
+
+    def __len__(self):
+        return len(self.db)
+
+    def __getitem__(self, key):
+        return self.db[key].decode("utf-8")
+
+    def __setitem__(self, key, value):
+        self.db[key] = value.encode("utf-8")
+
+    def __delitem__(self, key):
+        del self.db[key]
+
+    def __iter__(self):
+        return iter(self.db)
+
+    def close(self):
+        self.db.close()
+
+    def keys(self):
+        return self.db.keys()
+
+    def has_key(self, key):
+        return self.db.has_key(key)
+
+    __contains__ = has_key
+
+    def values(self):
+        for v in self.db.values():
+            yield v.decode("utf-8")
+
+    def items(self):
+        for k,v in self.db.items():
+            yield k, v.decode("utf-8")
+
+    def set_location(self, key):
+        return self.db.set_location(key)
+
+    def next(self):
+        key, value = self.db.next()
+        return key, value.decode("utf-8")
+
+    def previous(self):
+        key, value = self.db.previous()
+        return key, value.decode("utf-8")
+
+    def first(self):
+        key, value = self.db.first()
+        return key, value.decode("utf-8")
+
+    def last(self):
+        key, value = self.db.last()
+        return key, value.decode("utf-8")
+
+    def sync(self):
+        return self.db.sync()
+
 
 #----------------------------------------------------------------------
 # Compatibility object factory functions
@@ -375,7 +497,7 @@
         if file is not None and os.path.isfile(file):
             os.unlink(file)
     else:
-        raise error, "flags should be one of 'r', 'w', 'c' or 'n'"
+        raise error, "flags should be one of 'r', 'w', 'c' or 'n', not "+repr(flag)
     return flags | db.DB_THREAD
 
 #----------------------------------------------------------------------

Modified: python/branches/py3k-struni/Lib/test/test_bsddb.py
==============================================================================
--- python/branches/py3k-struni/Lib/test/test_bsddb.py	(original)
+++ python/branches/py3k-struni/Lib/test/test_bsddb.py	Sun Aug  5 17:39:16 2007
@@ -12,8 +12,12 @@
 class TestBSDDB(unittest.TestCase):
     openflag = 'c'
 
+    def do_open(self, *args, **kw):
+        # openmethod is a list so that it's not mistaken as an instance method
+        return bsddb.StringValues(bsddb.StringKeys(self.openmethod[0](*args, **kw)))
+
     def setUp(self):
-        self.f = self.openmethod[0](self.fname, self.openflag, cachesize=32768)
+        self.f = self.do_open(self.fname, self.openflag, cachesize=32768)
         self.d = dict(q='Guido', w='van', e='Rossum', r='invented', t='Python', y='')
         for k, v in self.d.items():
             self.f[k] = v
@@ -47,7 +51,7 @@
             # so finish here.
             return
         self.f.close()
-        self.f = self.openmethod[0](self.fname, 'w')
+        self.f = self.do_open(self.fname, 'w')
         for k, v in self.d.items():
             self.assertEqual(self.f[k], v)
 

Modified: python/branches/py3k-struni/Modules/_bsddb.c
==============================================================================
--- python/branches/py3k-struni/Modules/_bsddb.c	(original)
+++ python/branches/py3k-struni/Modules/_bsddb.c	Sun Aug  5 17:39:16 2007
@@ -99,7 +99,7 @@
 #endif
 
 #define PY_BSDDB_VERSION "4.5.0"
-static char *rcs_id = "$Id$";
+static char *svn_id = "$Id$";
 
 
 #if (PY_VERSION_HEX < 0x02050000)
@@ -413,7 +413,7 @@
         /* no need to do anything, the structure has already been zeroed */
     }
 
-    else if (PyString_Check(keyobj)) {
+    else if (PyBytes_Check(keyobj)) {
         /* verify access method type */
         type = _DB_get_type(self);
         if (type == -1)
@@ -425,8 +425,8 @@
             return 0;
         }
 
-        key->data = PyString_AS_STRING(keyobj);
-        key->size = PyString_GET_SIZE(keyobj);
+        key->data = PyBytes_AS_STRING(keyobj);
+        key->size = PyBytes_GET_SIZE(keyobj);
     }
 
     else if (PyInt_Check(keyobj)) {
@@ -460,7 +460,7 @@
     }
     else {
         PyErr_Format(PyExc_TypeError,
-                     "String or Integer object expected for key, %s found",
+                     "Bytes or Integer object expected for key, %s found",
                      Py_Type(keyobj)->tp_name);
         return 0;
     }
@@ -721,13 +721,13 @@
 
         case DB_RECNO:
         case DB_QUEUE:
-            retval = Py_BuildValue("is#", *((db_recno_t*)key.data),
+            retval = Py_BuildValue("iy#", *((db_recno_t*)key.data),
                                    data.data, data.size);
             break;
         case DB_HASH:
         case DB_BTREE:
         default:
-            retval = Py_BuildValue("s#s#", key.data, key.size,
+            retval = Py_BuildValue("y#y#", key.data, key.size,
                                    data.data, data.size);
             break;
         }
@@ -1196,18 +1196,13 @@
         else if (PyInt_Check(result)) {
             retval = PyInt_AsLong(result);
         }
-        else if (PyString_Check(result)) {
+        else if (PyBytes_Check(result)) {
             char* data;
             Py_ssize_t size;
 
             CLEAR_DBT(*secKey);
-#if PYTHON_API_VERSION <= 1007
-            /* 1.5 compatibility */
-            size = PyString_Size(result);
-            data = PyString_AsString(result);
-#else
-            PyString_AsStringAndSize(result, &data, &size);
-#endif
+            size = PyBytes_Size(result);
+            data = PyBytes_AsString(result);
             secKey->flags = DB_DBT_APPMALLOC;   /* DB will free */
             secKey->data = malloc(size);        /* TODO, check this */
 	    if (secKey->data) {
@@ -1548,7 +1543,7 @@
             retval = Py_BuildValue("s#s#", key.data, key.size, data.data,
                                    data.size);
         else /* return just the data */
-            retval = PyString_FromStringAndSize((char*)data.data, data.size);
+            retval = PyBytes_FromStringAndSize((char*)data.data, data.size);
         FREE_DBT(data);
     }
     FREE_DBT(key);
@@ -1617,13 +1612,13 @@
     else if (!err) {
         PyObject *pkeyObj;
         PyObject *dataObj;
-        dataObj = PyString_FromStringAndSize(data.data, data.size);
+        dataObj = PyBytes_FromStringAndSize(data.data, data.size);
 
         if (self->primaryDBType == DB_RECNO ||
             self->primaryDBType == DB_QUEUE)
             pkeyObj = PyInt_FromLong(*(int *)pkey.data);
         else
-            pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
+            pkeyObj = PyBytes_FromStringAndSize(pkey.data, pkey.size);
 
         if (flags & DB_SET_RECNO) /* return key , pkey and data */
         {
@@ -1632,7 +1627,7 @@
             if (type == DB_RECNO || type == DB_QUEUE)
                 keyObj = PyInt_FromLong(*(int *)key.data);
             else
-                keyObj = PyString_FromStringAndSize(key.data, key.size);
+                keyObj = PyBytes_FromStringAndSize(key.data, key.size);
 #if (PY_VERSION_HEX >= 0x02040000)
             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
 #else
@@ -1753,7 +1748,7 @@
     }
     else if (!err) {
         /* XXX(nnorwitz): can we do: retval = dataobj; Py_INCREF(retval); */
-        retval = PyString_FromStringAndSize((char*)data.data, data.size);
+        retval = PyBytes_FromStringAndSize((char*)data.data, data.size);
 
         /* Even though the flags require DB_DBT_MALLOC, data is not always
            allocated.  4.4: allocated, 4.5: *not* allocated. :-( */
@@ -2801,7 +2796,7 @@
         retval = NULL;
     }
     else {
-        retval = PyString_FromStringAndSize((char*)data.data, data.size);
+        retval = PyBytes_FromStringAndSize((char*)data.data, data.size);
         FREE_DBT(data);
     }
 
@@ -2952,7 +2947,7 @@
             case DB_BTREE:
             case DB_HASH:
             default:
-                item = PyString_FromStringAndSize((char*)key.data, key.size);
+                item = PyBytes_FromStringAndSize((char*)key.data, key.size);
                 break;
             case DB_RECNO:
             case DB_QUEUE:
@@ -2962,7 +2957,7 @@
             break;
 
         case _VALUES_LIST:
-            item = PyString_FromStringAndSize((char*)data.data, data.size);
+            item = PyBytes_FromStringAndSize((char*)data.data, data.size);
             break;
 
         case _ITEMS_LIST:
@@ -3303,13 +3298,13 @@
     else {
         PyObject *pkeyObj;
         PyObject *dataObj;
-        dataObj = PyString_FromStringAndSize(data.data, data.size);
+        dataObj = PyBytes_FromStringAndSize(data.data, data.size);
 
         if (self->mydb->primaryDBType == DB_RECNO ||
             self->mydb->primaryDBType == DB_QUEUE)
             pkeyObj = PyInt_FromLong(*(int *)pkey.data);
         else
-            pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size);
+            pkeyObj = PyBytes_FromStringAndSize(pkey.data, pkey.size);
 
         if (key.data && key.size) /* return key, pkey and data */
         {
@@ -3318,7 +3313,7 @@
             if (type == DB_RECNO || type == DB_QUEUE)
                 keyObj = PyInt_FromLong(*(int *)key.data);
             else
-                keyObj = PyString_FromStringAndSize(key.data, key.size);
+                keyObj = PyBytes_FromStringAndSize(key.data, key.size);
 #if (PY_VERSION_HEX >= 0x02040000)
             retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj);
 #else
@@ -4610,7 +4605,7 @@
     if (log_list) {
         char **log_list_start;
         for (log_list_start = log_list; *log_list != NULL; ++log_list) {
-            item = PyString_FromString (*log_list);
+            item = PyUnicode_FromString (*log_list);
             if (item == NULL) {
                 Py_DECREF(list);
                 list = NULL;
@@ -4910,7 +4905,7 @@
 
     RETURN_IF_ERR();
 
-    return PyString_FromStringAndSize(key.data, key.size);
+    return PyBytes_FromStringAndSize(key.data, key.size);
 }
 
 static PyObject*
@@ -5335,7 +5330,7 @@
         if (self->db_env->db_home == NULL) {
             RETURN_NONE();
         }
-        return PyString_FromString(self->db_env->db_home);
+        return PyUnicode_FromString(self->db_env->db_home);
     }
 
     return Py_FindMethod(DBEnv_methods, (PyObject* )self, name);
@@ -5654,9 +5649,9 @@
 {
     PyObject* m;
     PyObject* d;
-    PyObject* pybsddb_version_s = PyString_FromString( PY_BSDDB_VERSION );
-    PyObject* db_version_s = PyString_FromString( DB_VERSION_STRING );
-    PyObject* cvsid_s = PyString_FromString( rcs_id );
+    PyObject* pybsddb_version_s = PyUnicode_FromString(PY_BSDDB_VERSION);
+    PyObject* db_version_s = PyUnicode_FromString(DB_VERSION_STRING);
+    PyObject* svnid_s = PyUnicode_FromString(svn_id);
 
     /* Initialize the type of the new type objects here; doing it here
        is required for portability to Windows without requiring C++. */
@@ -5683,12 +5678,12 @@
     /* Add some symbolic constants to the module */
     d = PyModule_GetDict(m);
     PyDict_SetItemString(d, "__version__", pybsddb_version_s);
-    PyDict_SetItemString(d, "cvsid", cvsid_s);
+    PyDict_SetItemString(d, "cvsid", svnid_s);
     PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s);
     Py_DECREF(pybsddb_version_s);
     pybsddb_version_s = NULL;
-    Py_DECREF(cvsid_s);
-    cvsid_s = NULL;
+    Py_DECREF(svnid_s);
+    svnid_s = NULL;
     Py_DECREF(db_version_s);
     db_version_s = NULL;
 


More information about the Python-3000-checkins mailing list