Commit 870dcb42 authored by Georg Brandl's avatar Georg Brandl

#8046: add context manager protocol support to mmap objects. Also add closed property.

parent debc57e8
...@@ -112,6 +112,18 @@ To map anonymous memory, -1 should be passed as the fileno along with the length ...@@ -112,6 +112,18 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
map.close() 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 The next example demonstrates how to create an anonymous map and exchange
data between the parent and child processes:: 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 ...@@ -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: Memory-mapped file objects support the following methods:
.. method:: close() .. method:: close()
Close the file. Subsequent calls to other methods of the object will Close the file. Subsequent calls to other methods of the object will
result in an exception being raised. result in an exception being raised.
.. attribute:: closed
True if the file is closed.
.. versionadded:: 3.2
.. method:: find(sub[, start[, end]]) .. method:: find(sub[, start[, end]])
Returns the lowest index in the object where the subsequence *sub* is 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 ...@@ -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 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 the mmap was created with :const:`ACCESS_READ`, then writing to it will
throw a :exc:`TypeError` exception. throw a :exc:`TypeError` exception.
...@@ -586,6 +586,20 @@ class MmapTests(unittest.TestCase): ...@@ -586,6 +586,20 @@ class MmapTests(unittest.TestCase):
pass pass
m.close() 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(): def test_main():
run_unittest(MmapTests) run_unittest(MmapTests)
......
...@@ -18,6 +18,12 @@ Core and Builtins ...@@ -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), '-') omitted the real part from the output,
- format(complex(0.0, 2.0), '-') included a sign and parentheses. - 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 Library
------- -------
......
...@@ -651,6 +651,31 @@ mmap_move_method(mmap_object *self, PyObject *args) ...@@ -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[] = { static struct PyMethodDef mmap_object_methods[] = {
{"close", (PyCFunction) mmap_close_method, METH_NOARGS}, {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
{"find", (PyCFunction) mmap_find_method, METH_VARARGS}, {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
...@@ -666,9 +691,17 @@ static struct PyMethodDef mmap_object_methods[] = { ...@@ -666,9 +691,17 @@ static struct PyMethodDef mmap_object_methods[] = {
{"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
{"write", (PyCFunction) mmap_write_method, METH_VARARGS}, {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
{"write_byte", (PyCFunction) mmap_write_byte_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 */ {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 */ /* Functions for treating an mmap'ed file as a buffer */
static int static int
...@@ -975,7 +1008,7 @@ static PyTypeObject mmap_object_type = { ...@@ -975,7 +1008,7 @@ static PyTypeObject mmap_object_type = {
0, /* tp_iternext */ 0, /* tp_iternext */
mmap_object_methods, /* tp_methods */ mmap_object_methods, /* tp_methods */
0, /* tp_members */ 0, /* tp_members */
0, /* tp_getset */ mmap_object_getset, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
0, /* tp_dict */ 0, /* tp_dict */
0, /* tp_descr_get */ 0, /* tp_descr_get */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment