Skip to content

Commit

Permalink
pythongh-111835: Add seekable method to mmap.mmap (pythongh-111852)
Browse files Browse the repository at this point in the history
  • Loading branch information
corona10 authored and aisk committed Feb 11, 2024
1 parent 881ecbb commit 3706873
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 12 deletions.
8 changes: 8 additions & 0 deletions Doc/library/mmap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
values are ``os.SEEK_CUR`` or ``1`` (seek relative to the current
position) and ``os.SEEK_END`` or ``2`` (seek relative to the file's end).

.. versionchanged:: 3.13
Return the new absolute position instead of ``None``.

.. method:: seekable()

Return whether the file supports seeking, and the return value is always ``True``.

.. versionadded:: 3.13

.. method:: size()

Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ ipaddress
* Add the :attr:`ipaddress.IPv4Address.ipv6_mapped` property, which returns the IPv4-mapped IPv6 address.
(Contributed by Charles Machalow in :gh:`109466`.)

mmap
----

* The :class:`mmap.mmap` class now has an :meth:`~mmap.mmap.seekable` method
that can be used where it requires a file-like object with seekable and
the :meth:`~mmap.mmap.seek` method return the new absolute position.
(Contributed by Donghee Na and Sylvie Liberman in :gh:`111835`.)

opcode
------

Expand Down
11 changes: 6 additions & 5 deletions Lib/test/test_mmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,12 @@ def test_basic(self):
self.assertEqual(end, PAGESIZE + 6)

# test seeking around (try to overflow the seek implementation)
m.seek(0,0)
self.assertTrue(m.seekable())
self.assertEqual(m.seek(0, 0), 0)
self.assertEqual(m.tell(), 0)
m.seek(42,1)
self.assertEqual(m.seek(42, 1), 42)
self.assertEqual(m.tell(), 42)
m.seek(0,2)
self.assertEqual(m.seek(0, 2), len(m))
self.assertEqual(m.tell(), len(m))

# Try to seek to negative position...
Expand Down Expand Up @@ -162,7 +163,7 @@ def test_access_parameter(self):

# Ensuring that readonly mmap can't be write() to
try:
m.seek(0,0)
m.seek(0, 0)
m.write(b'abc')
except TypeError:
pass
Expand All @@ -171,7 +172,7 @@ def test_access_parameter(self):

# Ensuring that readonly mmap can't be write_byte() to
try:
m.seek(0,0)
m.seek(0, 0)
m.write_byte(b'd')
except TypeError:
pass
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The :class:`mmap.mmap` class now has an :meth:`~mmap.mmap.seekable` method
that can be used where it requires a file-like object with seekable and
the :meth:`~mmap.mmap.seek` method return the new absolute position.
Patch by Donghee Na.
21 changes: 14 additions & 7 deletions Modules/mmapmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ mmap_object_dealloc(mmap_object *m_obj)
}

static PyObject *
mmap_close_method(mmap_object *self, PyObject *unused)
mmap_close_method(mmap_object *self, PyObject *Py_UNUSED(ignored))
{
if (self->exports > 0) {
PyErr_SetString(PyExc_BufferError, "cannot close "\
Expand Down Expand Up @@ -260,7 +260,7 @@ do { \

static PyObject *
mmap_read_byte_method(mmap_object *self,
PyObject *unused)
PyObject *Py_UNUSED(ignored))
{
CHECK_VALID(NULL);
if (self->pos >= self->size) {
Expand All @@ -272,7 +272,7 @@ mmap_read_byte_method(mmap_object *self,

static PyObject *
mmap_read_line_method(mmap_object *self,
PyObject *unused)
PyObject *Py_UNUSED(ignored))
{
Py_ssize_t remaining;
char *start, *eol;
Expand Down Expand Up @@ -460,7 +460,7 @@ mmap_write_byte_method(mmap_object *self,

static PyObject *
mmap_size_method(mmap_object *self,
PyObject *unused)
PyObject *Py_UNUSED(ignored))
{
CHECK_VALID(NULL);

Expand Down Expand Up @@ -657,7 +657,7 @@ mmap_resize_method(mmap_object *self,
}

static PyObject *
mmap_tell_method(mmap_object *self, PyObject *unused)
mmap_tell_method(mmap_object *self, PyObject *Py_UNUSED(ignored))
{
CHECK_VALID(NULL);
return PyLong_FromSize_t(self->pos);
Expand Down Expand Up @@ -729,14 +729,20 @@ mmap_seek_method(mmap_object *self, PyObject *args)
if (where > self->size || where < 0)
goto onoutofrange;
self->pos = where;
Py_RETURN_NONE;
return PyLong_FromSsize_t(self->pos);
}

onoutofrange:
PyErr_SetString(PyExc_ValueError, "seek out of range");
return NULL;
}

static PyObject *
mmap_seekable_method(mmap_object *self, PyObject *Py_UNUSED(ignored))
{
Py_RETURN_TRUE;
}

static PyObject *
mmap_move_method(mmap_object *self, PyObject *args)
{
Expand Down Expand Up @@ -835,7 +841,7 @@ mmap__repr__method(PyObject *self)

#ifdef MS_WINDOWS
static PyObject *
mmap__sizeof__method(mmap_object *self, void *unused)
mmap__sizeof__method(mmap_object *self, void *Py_UNUSED(ignored))
{
size_t res = _PyObject_SIZE(Py_TYPE(self));
if (self->tagname) {
Expand Down Expand Up @@ -905,6 +911,7 @@ static struct PyMethodDef mmap_object_methods[] = {
{"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
{"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
{"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
{"seekable", (PyCFunction) mmap_seekable_method, METH_NOARGS},
{"size", (PyCFunction) mmap_size_method, METH_NOARGS},
{"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
{"write", (PyCFunction) mmap_write_method, METH_VARARGS},
Expand Down

0 comments on commit 3706873

Please sign in to comment.