summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/dbm.rst9
-rw-r--r--Lib/dbm/dumb.py4
-rwxr-xr-xLib/test/test_dbm_gnu.py4
-rw-r--r--Misc/NEWS4
-rw-r--r--Modules/_gdbmmodule.c47
5 files changed, 63 insertions, 5 deletions
diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst
index 6926ca6..67c0025 100644
--- a/Doc/library/dbm.rst
+++ b/Doc/library/dbm.rst
@@ -61,10 +61,15 @@ the Oracle Berkeley DB.
modified by the prevailing umask).
-The object returned by :func:`.open` supports most of the same functionality as
+The object returned by :func:`.open` supports the same basic functionality as
dictionaries; keys and their corresponding values can be stored, retrieved, and
deleted, and the :keyword:`in` operator and the :meth:`keys` method are
-available. Key and values are always stored as bytes. This means that when
+available, as well as :meth:`get` and :meth:`setdefault`.
+
+.. versionchanged:: 3.2
+ :meth:`get` and :meth:`setdefault` are now available in all database modules.
+
+Key and values are always stored as bytes. This means that when
strings are used they are implicitly converted to the default encoding before
being stored.
diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py
index 4d804da..cfb9123 100644
--- a/Lib/dbm/dumb.py
+++ b/Lib/dbm/dumb.py
@@ -203,7 +203,7 @@ class _Database(collections.MutableMapping):
# The blocks used by the associated value are lost.
del self._index[key]
# XXX It's unclear why we do a _commit() here (the code always
- # XXX has, so I'm not changing it). _setitem__ doesn't try to
+ # XXX has, so I'm not changing it). __setitem__ doesn't try to
# XXX keep the directory file in synch. Why should we? Or
# XXX why shouldn't __setitem__?
self._commit()
@@ -232,7 +232,7 @@ class _Database(collections.MutableMapping):
__del__ = close
- def _chmod (self, file):
+ def _chmod(self, file):
if hasattr(self._os, 'chmod'):
self._os.chmod(file, self._mode)
diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py
index dad56e6..ce96ce4 100755
--- a/Lib/test/test_dbm_gnu.py
+++ b/Lib/test/test_dbm_gnu.py
@@ -32,6 +32,10 @@ class TestGdbm(unittest.TestCase):
key_set.remove(key)
key = self.g.nextkey(key)
self.assertRaises(KeyError, lambda: self.g['xxx'])
+ # get() and setdefault() work as in the dict interface
+ self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo')
+ self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo')
+ self.assertEqual(self.g[b'xxx'], b'foo')
def test_error_conditions(self):
# Try to open a non-existent database.
diff --git a/Misc/NEWS b/Misc/NEWS
index f53a486..bc4cd25 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -37,7 +37,9 @@ Core and Builtins
Library
-------
-- Issue 10620: `python -m unittest` can accept file paths instead of module
+- Issue #6045: dbm.gnu databases now support get() and setdefault() methods.
+
+- Issue #10620: `python -m unittest` can accept file paths instead of module
names for running specific tests.
- Issue #9424: Deprecate the `unittest.TestCase` methods `assertEquals`,
diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c
index f15fefd..474561b 100644
--- a/Modules/_gdbmmodule.c
+++ b/Modules/_gdbmmodule.c
@@ -135,6 +135,28 @@ dbm_subscript(dbmobject *dp, register PyObject *key)
return v;
}
+PyDoc_STRVAR(dbm_get__doc__,
+"get(key[, default]) -> value\n\
+Get the value for key, or default if not present; if not given,\n\
+default is None.");
+
+static PyObject *
+dbm_get(dbmobject *dp, PyObject *args)
+{
+ PyObject *v, *res;
+ PyObject *def = Py_None;
+
+ if (!PyArg_UnpackTuple(args, "get", 1, 2, &v, &def))
+ return NULL;
+ res = dbm_subscript(dp, v);
+ if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ Py_INCREF(def);
+ return def;
+ }
+ return res;
+}
+
static int
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
{
@@ -176,6 +198,29 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
return 0;
}
+PyDoc_STRVAR(dbm_setdefault__doc__,
+"setdefault(key[, default]) -> value\n\
+Get value for key, or set it to default and return default if not present;\n\
+if not given, default is None.");
+
+static PyObject *
+dbm_setdefault(dbmobject *dp, PyObject *args)
+{
+ PyObject *v, *res;
+ PyObject *def = Py_None;
+
+ if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &v, &def))
+ return NULL;
+ res = dbm_subscript(dp, v);
+ if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ if (dbm_ass_sub(dp, v, def) < 0)
+ return NULL;
+ return dbm_subscript(dp, v);
+ }
+ return res;
+}
+
static PyMappingMethods dbm_as_mapping = {
(lenfunc)dbm_length, /*mp_length*/
(binaryfunc)dbm_subscript, /*mp_subscript*/
@@ -378,6 +423,8 @@ static PyMethodDef dbm_methods[] = {
{"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
{"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
{"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__},
+ {"get", (PyCFunction)dbm_get, METH_VARARGS, dbm_get__doc__},
+ {"setdefault",(PyCFunction)dbm_setdefault,METH_VARARGS, dbm_setdefault__doc__},
{NULL, NULL} /* sentinel */
};