From c608ef01e0889e29679dc01f9aeadc5a2b390181 Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Fri, 17 Apr 2020 08:28:32 -0600 Subject: [PATCH] bpo-32494: Add gdbm.count() gdbm_count() was added in GDBM 1.11. --- Doc/library/dbm.rst | 7 +++++ Lib/test/test_dbm_gnu.py | 28 ++++++++++++++----- .../2020-04-17-08-28-08.bpo-32494.k4zxIG.rst | 2 ++ Modules/_gdbmmodule.c | 27 ++++++++++++++++++ Modules/clinic/_gdbmmodule.c.h | 28 ++++++++++++++++++- 5 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-04-17-08-28-08.bpo-32494.k4zxIG.rst diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst index 57ae547b833cc0..aad737566cb50b 100644 --- a/Doc/library/dbm.rst +++ b/Doc/library/dbm.rst @@ -237,6 +237,13 @@ supported. Close the ``gdbm`` database. + .. method:: gdbm.count() + + Count the number of records in the database. This method requires GNU + DBM version 1.11 or greater. + + .. versionadded:: 3.9 + :mod:`dbm.ndbm` --- Interface based on ndbm ------------------------------------------- diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py index f1c7d34085c5ee..2a5b99f07b6387 100644 --- a/Lib/test/test_dbm_gnu.py +++ b/Lib/test/test_dbm_gnu.py @@ -4,19 +4,18 @@ import os from test.support import TESTFN, TESTFN_NONASCII, unlink +try: + from _gdbm import _GDBM_VERSION as gdbm_version +except ImportError: + gdbm_version = None filename = TESTFN class TestGdbm(unittest.TestCase): @staticmethod def setUpClass(): - if support.verbose: - try: - from _gdbm import _GDBM_VERSION as version - except ImportError: - pass - else: - print(f"gdbm version: {version}") + if support.verbose and gdbm_version: + print(f"gdbm version: {gdbm_version}") def setUp(self): self.g = None @@ -162,6 +161,21 @@ def test_nonexisting_file(self): self.assertIn(nonexisting_file, str(cm.exception)) self.assertEqual(cm.exception.filename, nonexisting_file) + @unittest.skipUnless(gdbm_version and gdbm_version >= (1, 11, 0), + 'needs >= 1.11') + def test_count(self): + self.g = gdbm.open(filename, 'c') + self.assertEqual(self.g.count(), 0) + + self.g['a'] = 'a' + self.assertEqual(self.g.count(), 1) + self.g['b'] = 'b' + self.assertEqual(self.g.count(), 2) + del self.g['a'] + self.assertEqual(self.g.count(), 1) + del self.g['b'] + self.assertEqual(self.g.count(), 0) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2020-04-17-08-28-08.bpo-32494.k4zxIG.rst b/Misc/NEWS.d/next/Library/2020-04-17-08-28-08.bpo-32494.k4zxIG.rst new file mode 100644 index 00000000000000..de82be31119ffb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-17-08-28-08.bpo-32494.k4zxIG.rst @@ -0,0 +1,2 @@ +Add :meth:`gdbm.count` to wrap the ``gdbm_count()`` function added in GDBM +1.11. diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index 7a9649b54119b3..d78246e7786b7c 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -486,6 +486,32 @@ _gdbm_gdbm_sync_impl(dbmobject *self) Py_RETURN_NONE; } +#if GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11 +/*[clinic input] +_gdbm.gdbm.count + +Count the number of records in the database. +[clinic start generated code]*/ + +static PyObject * +_gdbm_gdbm_count_impl(dbmobject *self) +/*[clinic end generated code: output=8b62b02ae4c2fcee input=1b9d3f0877315a04]*/ +{ + gdbm_count_t count; + check_dbmobject_open(self); + if (gdbm_count(self->di_dbm, &count) == -1) { + if (errno != 0) { + PyErr_SetFromErrno(DbmError); + } + else { + PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); + } + return NULL; + } + return PyLong_FromUnsignedLongLong(count); +} +#endif + static PyObject * dbm__enter__(PyObject *self, PyObject *args) { @@ -509,6 +535,7 @@ static PyMethodDef dbm_methods[] = { _GDBM_GDBM_SYNC_METHODDEF _GDBM_GDBM_GET_METHODDEF _GDBM_GDBM_SETDEFAULT_METHODDEF + _GDBM_GDBM_COUNT_METHODDEF {"__enter__", dbm__enter__, METH_NOARGS, NULL}, {"__exit__", dbm__exit__, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ diff --git a/Modules/clinic/_gdbmmodule.c.h b/Modules/clinic/_gdbmmodule.c.h index aa37a24d3b2115..496308c8a2b966 100644 --- a/Modules/clinic/_gdbmmodule.c.h +++ b/Modules/clinic/_gdbmmodule.c.h @@ -211,6 +211,28 @@ _gdbm_gdbm_sync(dbmobject *self, PyObject *Py_UNUSED(ignored)) return _gdbm_gdbm_sync_impl(self); } +#if (GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11) + +PyDoc_STRVAR(_gdbm_gdbm_count__doc__, +"count($self, /)\n" +"--\n" +"\n" +"Count the number of records in the database."); + +#define _GDBM_GDBM_COUNT_METHODDEF \ + {"count", (PyCFunction)_gdbm_gdbm_count, METH_NOARGS, _gdbm_gdbm_count__doc__}, + +static PyObject * +_gdbm_gdbm_count_impl(dbmobject *self); + +static PyObject * +_gdbm_gdbm_count(dbmobject *self, PyObject *Py_UNUSED(ignored)) +{ + return _gdbm_gdbm_count_impl(self); +} + +#endif /* (GDBM_VERSION_MAJOR >= 1 && GDBM_VERSION_MINOR >= 11) */ + PyDoc_STRVAR(dbmopen__doc__, "open($module, filename, flags=\'r\', mode=0o666, /)\n" "--\n" @@ -298,4 +320,8 @@ dbmopen(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=2766471b2fa1a816 input=a9049054013a1b77]*/ + +#ifndef _GDBM_GDBM_COUNT_METHODDEF + #define _GDBM_GDBM_COUNT_METHODDEF +#endif /* !defined(_GDBM_GDBM_COUNT_METHODDEF) */ +/*[clinic end generated code: output=0373bfdb5c23b602 input=a9049054013a1b77]*/