diff options
-rw-r--r-- | Doc/library/mmap.rst | 22 | ||||
-rw-r--r-- | Lib/test/test_mmap.py | 14 | ||||
-rw-r--r-- | Misc/NEWS | 6 | ||||
-rw-r--r-- | Modules/mmapmodule.c | 35 |
4 files changed, 73 insertions, 4 deletions
diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 403e2f5..3e0854b 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -112,6 +112,18 @@ To map anonymous memory, -1 should be passed as the fileno along with the length map.close() + :class:`mmap` can also be used as a context manager in a :keyword:`with` + statement.:: + + import mmap + + with mmap.mmap(-1, 13) as map: + map.write("Hello world!") + + .. versionadded:: 3.2 + Context manager support. + + The next example demonstrates how to create an anonymous map and exchange data between the parent and child processes:: @@ -132,13 +144,19 @@ To map anonymous memory, -1 should be passed as the fileno along with the length Memory-mapped file objects support the following methods: - .. method:: close() Close the file. Subsequent calls to other methods of the object will result in an exception being raised. + .. attribute:: closed + + True if the file is closed. + + .. versionadded:: 3.2 + + .. method:: find(sub[, start[, end]]) Returns the lowest index in the object where the subsequence *sub* is @@ -236,5 +254,3 @@ To map anonymous memory, -1 should be passed as the fileno along with the length position of the file pointer; the file position is advanced by ``1``. If the mmap was created with :const:`ACCESS_READ`, then writing to it will throw a :exc:`TypeError` exception. - - diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index c27b898..68af00e 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -586,6 +586,20 @@ class MmapTests(unittest.TestCase): pass m.close() + def test_context_manager(self): + with mmap.mmap(-1, 10) as m: + self.assertFalse(m.closed) + self.assertTrue(m.closed) + + def test_context_manager_exception(self): + # Test that the IOError gets passed through + with self.assertRaises(Exception) as exc: + with mmap.mmap(-1, 10) as m: + raise IOError + self.assertIsInstance(exc.exception, IOError, + "wrong exception raised in context manager") + self.assertTrue(m.closed, "context manager failed") + def test_main(): run_unittest(MmapTests) @@ -18,6 +18,12 @@ Core and Builtins - format(complex(-0.0, 2.0), '-') omitted the real part from the output, - format(complex(0.0, 2.0), '-') included a sign and parentheses. +Extensions +---------- + +- Issue #8046: Add context manager protocol support and .closed property + to mmap objects. + Library ------- diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 9714ddf..de527ce 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -651,6 +651,31 @@ mmap_move_method(mmap_object *self, PyObject *args) } } +static PyObject * +mmap_closed_get(mmap_object *self) +{ +#ifdef MS_WINDOWS + return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); +#elif defined(UNIX) + return PyBool_FromLong(self->data == NULL ? 1 : 0); +#endif +} + +static PyObject * +mmap__enter__method(mmap_object *self, PyObject *args) +{ + CHECK_VALID(NULL); + + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +mmap__exit__method(PyObject *self, PyObject *args) +{ + return PyObject_CallMethod(self, "close", NULL); +} + static struct PyMethodDef mmap_object_methods[] = { {"close", (PyCFunction) mmap_close_method, METH_NOARGS}, {"find", (PyCFunction) mmap_find_method, METH_VARARGS}, @@ -666,9 +691,17 @@ static struct PyMethodDef mmap_object_methods[] = { {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, {"write", (PyCFunction) mmap_write_method, METH_VARARGS}, {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS}, + {"__enter__", (PyCFunction) mmap__enter__method, METH_NOARGS}, + {"__exit__", (PyCFunction) mmap__exit__method, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; +static PyGetSetDef mmap_object_getset[] = { + {"closed", (getter) mmap_closed_get, NULL, NULL}, + {NULL} +}; + + /* Functions for treating an mmap'ed file as a buffer */ static int @@ -975,7 +1008,7 @@ static PyTypeObject mmap_object_type = { 0, /* tp_iternext */ mmap_object_methods, /* tp_methods */ 0, /* tp_members */ - 0, /* tp_getset */ + mmap_object_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ |