diff -r 72837ba10a83 Doc/library/dbm.rst --- a/Doc/library/dbm.rst Fri Oct 18 11:55:30 2013 +0300 +++ b/Doc/library/dbm.rst Sat Oct 19 09:25:31 2013 +0300 @@ -61,6 +61,10 @@ modified by the prevailing umask). +.. versionchanged:: 3.4 + Support for the :keyword:`with` statement was added for :func:`.open`. + + 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 diff -r 72837ba10a83 Lib/dbm/dumb.py --- a/Lib/dbm/dumb.py Fri Oct 18 11:55:30 2013 +0300 +++ b/Lib/dbm/dumb.py Sat Oct 19 09:25:31 2013 +0300 @@ -236,6 +236,12 @@ if hasattr(self._os, 'chmod'): self._os.chmod(file, self._mode) + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + def open(file, flag=None, mode=0o666): """Open the database file, filename, and return corresponding object. diff -r 72837ba10a83 Lib/test/test_dbm_dumb.py --- a/Lib/test/test_dbm_dumb.py Fri Oct 18 11:55:30 2013 +0300 +++ b/Lib/test/test_dbm_dumb.py Sat Oct 19 09:25:31 2013 +0300 @@ -186,6 +186,13 @@ self.assertEqual(expected, got) f.close() + def test_context_manager(self): + with dumbdbm.open(_fname, 'c') as db: + db["dumbdbm context manager"] = "context manager" + + with dumbdbm.open(_fname, 'r') as db: + self.assertEqual(list(db.keys()), [b"dumbdbm context manager"]) + def tearDown(self): _delete_files() diff -r 72837ba10a83 Lib/test/test_dbm_gnu.py --- a/Lib/test/test_dbm_gnu.py Fri Oct 18 11:55:30 2013 +0300 +++ b/Lib/test/test_dbm_gnu.py Sat Oct 19 09:25:31 2013 +0300 @@ -80,6 +80,17 @@ size2 = os.path.getsize(filename) self.assertTrue(size1 > size2 >= size0) + def test_context_manager(self): + with gdbm.open(filename, 'c') as db: + db["gdbm context manager"] = "context manager" + + with gdbm.open(filename, 'r') as db: + self.assertEqual(list(db.keys()), [b"gdbm context manager"]) + + with self.assertRaises(gdbm.error) as cm: + db.keys() + self.assertEqual(str(cm.exception), + "GDBM object has already been closed") if __name__ == '__main__': unittest.main() diff -r 72837ba10a83 Lib/test/test_dbm_ndbm.py --- a/Lib/test/test_dbm_ndbm.py Fri Oct 18 11:55:30 2013 +0300 +++ b/Lib/test/test_dbm_ndbm.py Sat Oct 19 09:25:31 2013 +0300 @@ -36,5 +36,18 @@ except error: self.fail() + def test_context_manager(self): + with dbm.ndbm.open(self.filename, 'c') as db: + db["ndbm context manager"] = "context manager" + + with dbm.ndbm.open(self.filename, 'r') as db: + self.assertEqual(list(db.keys()), [b"ndbm context manager"]) + + with self.assertRaises(dbm.ndbm.error) as cm: + db.keys() + self.assertEqual(str(cm.exception), + "DBM object has already been closed") + + if __name__ == '__main__': unittest.main() diff -r 72837ba10a83 Misc/NEWS --- a/Misc/NEWS Fri Oct 18 11:55:30 2013 +0300 +++ b/Misc/NEWS Sat Oct 19 09:25:31 2013 +0300 @@ -42,6 +42,7 @@ Library ------- +- Issue #19282: dbm.open now supports the context manager protocol. - Issue #19262: Initial check in of the 'asyncio' package (a.k.a. Tulip, a.k.a. PEP 3156). There are no docs yet, and the PEP is slightly diff -r 72837ba10a83 Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c Fri Oct 18 11:55:30 2013 +0300 +++ b/Modules/_dbmmodule.c Sat Oct 19 09:25:31 2013 +0300 @@ -313,6 +313,21 @@ return defvalue; } +static PyObject * +dbm__enter__(dbmobject *self, PyObject *args) +{ + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +dbm__exit__(dbmobject *self, PyObject *args) +{ + _Py_IDENTIFIER(close); + return _PyObject_CallMethodId(self, &PyId_close, NULL); +} + + static PyMethodDef dbm_methods[] = { {"close", (PyCFunction)dbm__close, METH_NOARGS, "close()\nClose the database."}, @@ -325,6 +340,8 @@ "setdefault(key[, default]) -> value\n" "Return the value for key if present, otherwise default. If key\n" "is not in the database, it is inserted with default as the value."}, + {"__enter__", (PyCFunction)dbm__enter__, METH_NOARGS, NULL}, + {"__exit__", (PyCFunction)dbm__exit__, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff -r 72837ba10a83 Modules/_gdbmmodule.c --- a/Modules/_gdbmmodule.c Fri Oct 18 11:55:30 2013 +0300 +++ b/Modules/_gdbmmodule.c Sat Oct 19 09:25:31 2013 +0300 @@ -416,6 +416,20 @@ return Py_None; } +static PyObject * +dbm__enter__(dbmobject *self, PyObject *args) +{ + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +dbm__exit__(dbmobject *self, PyObject *args) +{ + _Py_IDENTIFIER(close); + return _PyObject_CallMethodId(self, &PyId_close, NULL); +} + static PyMethodDef dbm_methods[] = { {"close", (PyCFunction)dbm_close, METH_NOARGS, dbm_close__doc__}, {"keys", (PyCFunction)dbm_keys, METH_NOARGS, dbm_keys__doc__}, @@ -425,6 +439,8 @@ {"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__}, + {"__enter__", (PyCFunction)dbm__enter__, METH_NOARGS, NULL}, + {"__exit__", (PyCFunction)dbm__exit__, METH_VARARGS, NULL}, {NULL, NULL} /* sentinel */ };