Skip to content

Commit d9e833c

Browse files
committed
python#6045: provide at least get() and setdefault() for all dbm modules.
1 parent da72231 commit d9e833c

5 files changed

Lines changed: 63 additions & 5 deletions

File tree

Doc/library/dbm.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ the Oracle Berkeley DB.
6161
modified by the prevailing umask).
6262

6363

64-
The object returned by :func:`.open` supports most of the same functionality as
64+
The object returned by :func:`.open` supports the same basic functionality as
6565
dictionaries; keys and their corresponding values can be stored, retrieved, and
6666
deleted, and the :keyword:`in` operator and the :meth:`keys` method are
67-
available. Key and values are always stored as bytes. This means that when
67+
available, as well as :meth:`get` and :meth:`setdefault`.
68+
69+
.. versionchanged:: 3.2
70+
:meth:`get` and :meth:`setdefault` are now available in all database modules.
71+
72+
Key and values are always stored as bytes. This means that when
6873
strings are used they are implicitly converted to the default encoding before
6974
being stored.
7075

Lib/dbm/dumb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def __delitem__(self, key):
203203
# The blocks used by the associated value are lost.
204204
del self._index[key]
205205
# XXX It's unclear why we do a _commit() here (the code always
206-
# XXX has, so I'm not changing it). _setitem__ doesn't try to
206+
# XXX has, so I'm not changing it). __setitem__ doesn't try to
207207
# XXX keep the directory file in synch. Why should we? Or
208208
# XXX why shouldn't __setitem__?
209209
self._commit()
@@ -232,7 +232,7 @@ def close(self):
232232

233233
__del__ = close
234234

235-
def _chmod (self, file):
235+
def _chmod(self, file):
236236
if hasattr(self._os, 'chmod'):
237237
self._os.chmod(file, self._mode)
238238

Lib/test/test_dbm_gnu.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ def test_key_methods(self):
3232
key_set.remove(key)
3333
key = self.g.nextkey(key)
3434
self.assertRaises(KeyError, lambda: self.g['xxx'])
35+
# get() and setdefault() work as in the dict interface
36+
self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo')
37+
self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo')
38+
self.assertEqual(self.g[b'xxx'], b'foo')
3539

3640
def test_error_conditions(self):
3741
# Try to open a non-existent database.

Misc/NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ Core and Builtins
3737
Library
3838
-------
3939

40-
- Issue 10620: `python -m unittest` can accept file paths instead of module
40+
- Issue #6045: dbm.gnu databases now support get() and setdefault() methods.
41+
42+
- Issue #10620: `python -m unittest` can accept file paths instead of module
4143
names for running specific tests.
4244

4345
- Issue #9424: Deprecate the `unittest.TestCase` methods `assertEquals`,

Modules/_gdbmmodule.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,28 @@ dbm_subscript(dbmobject *dp, register PyObject *key)
135135
return v;
136136
}
137137

138+
PyDoc_STRVAR(dbm_get__doc__,
139+
"get(key[, default]) -> value\n\
140+
Get the value for key, or default if not present; if not given,\n\
141+
default is None.");
142+
143+
static PyObject *
144+
dbm_get(dbmobject *dp, PyObject *args)
145+
{
146+
PyObject *v, *res;
147+
PyObject *def = Py_None;
148+
149+
if (!PyArg_UnpackTuple(args, "get", 1, 2, &v, &def))
150+
return NULL;
151+
res = dbm_subscript(dp, v);
152+
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
153+
PyErr_Clear();
154+
Py_INCREF(def);
155+
return def;
156+
}
157+
return res;
158+
}
159+
138160
static int
139161
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
140162
{
@@ -176,6 +198,29 @@ dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
176198
return 0;
177199
}
178200

201+
PyDoc_STRVAR(dbm_setdefault__doc__,
202+
"setdefault(key[, default]) -> value\n\
203+
Get value for key, or set it to default and return default if not present;\n\
204+
if not given, default is None.");
205+
206+
static PyObject *
207+
dbm_setdefault(dbmobject *dp, PyObject *args)
208+
{
209+
PyObject *v, *res;
210+
PyObject *def = Py_None;
211+
212+
if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &v, &def))
213+
return NULL;
214+
res = dbm_subscript(dp, v);
215+
if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
216+
PyErr_Clear();
217+
if (dbm_ass_sub(dp, v, def) < 0)
218+
return NULL;
219+
return dbm_subscript(dp, v);
220+
}
221+
return res;
222+
}
223+
179224
static PyMappingMethods dbm_as_mapping = {
180225
(lenfunc)dbm_length, /*mp_length*/
181226
(binaryfunc)dbm_subscript, /*mp_subscript*/
@@ -378,6 +423,8 @@ static PyMethodDef dbm_methods[] = {
378423
{"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
379424
{"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
380425
{"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__},
426+
{"get", (PyCFunction)dbm_get, METH_VARARGS, dbm_get__doc__},
427+
{"setdefault",(PyCFunction)dbm_setdefault,METH_VARARGS, dbm_setdefault__doc__},
381428
{NULL, NULL} /* sentinel */
382429
};
383430

0 commit comments

Comments
 (0)