From 4dd453c6aab315954f19bf0b2f1541c2b37d8e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Fran=C3=A7ois=20Natali?= Date: Wed, 8 Jun 2011 19:18:14 +0200 Subject: Issue #12021: Make mmap's read() method argument optional. Patch by Petri Lehtinen. --- Doc/library/mmap.rst | 12 ++++++++---- Lib/test/test_mmap.py | 29 +++++++++++++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ Modules/mmapmodule.c | 26 ++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index 7a901c9..7708028 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -190,12 +190,16 @@ To map anonymous memory, -1 should be passed as the fileno along with the length move will raise a :exc:`TypeError` exception. - .. method:: read(num) + .. method:: read([n]) - Return a :class:`bytes` containing up to *num* bytes starting from the - current file position; the file position is updated to point after the - bytes that were returned. + Return a :class:`bytes` containing up to *n* bytes starting from the + current file position. If the argument is omitted, *None* or negative, + return all bytes from the current file position to the end of the + mapping. The file position is updated to point after the bytes that were + returned. + .. versionchanged:: 3.3 + Argument can be omitted or *None*. .. method:: read_byte() diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 712378b..4bbb19b 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -417,6 +417,35 @@ class MmapTests(unittest.TestCase): m[x] = b self.assertEqual(m[x], b) + def test_read_all(self): + m = mmap.mmap(-1, 16) + self.addCleanup(m.close) + + # With no parameters, or None or a negative argument, reads all + m.write(bytes(range(16))) + m.seek(0) + self.assertEqual(m.read(), bytes(range(16))) + m.seek(8) + self.assertEqual(m.read(), bytes(range(8, 16))) + m.seek(16) + self.assertEqual(m.read(), b'') + m.seek(3) + self.assertEqual(m.read(None), bytes(range(3, 16))) + m.seek(4) + self.assertEqual(m.read(-1), bytes(range(4, 16))) + m.seek(5) + self.assertEqual(m.read(-2), bytes(range(5, 16))) + m.seek(9) + self.assertEqual(m.read(-42), bytes(range(9, 16))) + + def test_read_invalid_arg(self): + m = mmap.mmap(-1, 16) + self.addCleanup(m.close) + + self.assertRaises(TypeError, m.read, 'foo') + self.assertRaises(TypeError, m.read, 5.5) + self.assertRaises(TypeError, m.read, [1, 2, 3]) + def test_extended_getslice(self): # Test extended slicing by comparing with list slicing. s = bytes(reversed(range(256))) diff --git a/Misc/ACKS b/Misc/ACKS index 08fc572..900fae7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -548,6 +548,7 @@ Vincent Legoll Kip Lehman Joerg Lehmann Robert Lehmann +Petri Lehtinen Luke Kenneth Casson Leighton Marc-Andre Lemburg John Lenton diff --git a/Misc/NEWS b/Misc/NEWS index 8a70ce9..1995b14 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -187,6 +187,9 @@ Core and Builtins Library ------- +- Issue #12021: Make mmap's read() method argument optional. Patch by Petri + Lehtinen. + - Issue #9205: concurrent.futures.ProcessPoolExecutor now detects killed children and raises BrokenProcessPool in such a situation. Previously it would reliably freeze/deadlock. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 38f6157..ab12e2c 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -240,15 +240,37 @@ mmap_read_line_method(mmap_object *self, return result; } +/* Basically the "n" format code with the ability to turn None into -1. */ +static int +mmap_convert_ssize_t(PyObject *obj, void *result) { + Py_ssize_t limit; + if (obj == Py_None) { + limit = -1; + } + else if (PyNumber_Check(obj)) { + limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); + if (limit == -1 && PyErr_Occurred()) + return 0; + } + else { + PyErr_Format(PyExc_TypeError, + "integer argument expected, got '%.200s'", + Py_TYPE(obj)->tp_name); + return 0; + } + *((Py_ssize_t *)result) = limit; + return 1; +} + static PyObject * mmap_read_method(mmap_object *self, PyObject *args) { - Py_ssize_t num_bytes, n; + Py_ssize_t num_bytes = -1, n; PyObject *result; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n:read", &num_bytes)) + if (!PyArg_ParseTuple(args, "|O&:read", mmap_convert_ssize_t, &num_bytes)) return(NULL); /* silently 'adjust' out-of-range requests */ -- cgit v0.12