Skip to content

Commit d8ca235

Browse files
thautwarmzhangyangyu
authored andcommitted
bpo-34953: Implement mmap.mmap.__repr__ (GH-9891)
1 parent 9c11029 commit d8ca235

File tree

2 files changed

+93
-12
lines changed

2 files changed

+93
-12
lines changed

Lib/test/test_mmap.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,42 @@ def test_flush_return_value(self):
740740
# See bpo-34754 for details.
741741
self.assertRaises(OSError, mm.flush, 1, len(b'python'))
742742

743+
def test_repr(self):
744+
open_mmap_repr_pat = re.compile(
745+
r"<mmap.mmap closed=False, "
746+
r"access=(?P<access>\S+), "
747+
r"length=(?P<length>\d+), "
748+
r"pos=(?P<pos>\d+), "
749+
r"offset=(?P<offset>\d+)>")
750+
closed_mmap_repr_pat = re.compile(r"<mmap.mmap closed=True>")
751+
mapsizes = (50, 100, 1_000, 1_000_000, 10_000_000)
752+
offsets = tuple((mapsize // 2 // mmap.ALLOCATIONGRANULARITY)
753+
* mmap.ALLOCATIONGRANULARITY for mapsize in mapsizes)
754+
for offset, mapsize in zip(offsets, mapsizes):
755+
data = b'a' * mapsize
756+
length = mapsize - offset
757+
accesses = ('ACCESS_DEFAULT', 'ACCESS_READ',
758+
'ACCESS_COPY', 'ACCESS_WRITE')
759+
positions = (0, length//10, length//5, length//4)
760+
with open(TESTFN, "wb+") as fp:
761+
fp.write(data)
762+
fp.flush()
763+
for access, pos in itertools.product(accesses, positions):
764+
accint = getattr(mmap, access)
765+
with mmap.mmap(fp.fileno(),
766+
length,
767+
access=accint,
768+
offset=offset) as mm:
769+
mm.seek(pos)
770+
match = open_mmap_repr_pat.match(repr(mm))
771+
self.assertIsNotNone(match)
772+
self.assertEqual(match.group('access'), access)
773+
self.assertEqual(match.group('length'), str(length))
774+
self.assertEqual(match.group('pos'), str(pos))
775+
self.assertEqual(match.group('offset'), str(offset))
776+
match = closed_mmap_repr_pat.match(repr(mm))
777+
self.assertIsNotNone(match)
778+
743779
@unittest.skipUnless(hasattr(mmap.mmap, 'madvise'), 'needs madvise')
744780
def test_madvise(self):
745781
size = 2 * PAGESIZE

Modules/mmapmodule.c

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,51 @@ mmap__exit__method(PyObject *self, PyObject *args)
695695
return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
696696
}
697697

698+
static PyObject *
699+
mmap__repr__method(PyObject *self)
700+
{
701+
mmap_object *mobj = (mmap_object *)self;
702+
703+
#ifdef MS_WINDOWS
704+
#define _Py_FORMAT_OFFSET "lld"
705+
if (mobj->map_handle == NULL)
706+
#elif defined(UNIX)
707+
# ifdef HAVE_LARGEFILE_SUPPORT
708+
# define _Py_FORMAT_OFFSET "lld"
709+
# else
710+
# define _Py_FORMAT_OFFSET "ld"
711+
# endif
712+
if (mobj->data == NULL)
713+
#endif
714+
{
715+
return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
716+
} else {
717+
const char *access_str;
718+
719+
switch (mobj->access) {
720+
case ACCESS_DEFAULT:
721+
access_str = "ACCESS_DEFAULT";
722+
break;
723+
case ACCESS_READ:
724+
access_str = "ACCESS_READ";
725+
break;
726+
case ACCESS_WRITE:
727+
access_str = "ACCESS_WRITE";
728+
break;
729+
case ACCESS_COPY:
730+
access_str = "ACCESS_COPY";
731+
break;
732+
default:
733+
Py_UNREACHABLE();
734+
}
735+
736+
return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
737+
"pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
738+
Py_TYPE(self)->tp_name, access_str,
739+
mobj->size, mobj->pos, mobj->offset);
740+
}
741+
}
742+
698743
#ifdef MS_WINDOWS
699744
static PyObject *
700745
mmap__sizeof__method(mmap_object *self, void *unused)
@@ -1044,23 +1089,23 @@ static PyTypeObject mmap_object_type = {
10441089
sizeof(mmap_object), /* tp_basicsize */
10451090
0, /* tp_itemsize */
10461091
/* methods */
1047-
(destructor) mmap_object_dealloc, /* tp_dealloc */
1092+
(destructor)mmap_object_dealloc, /* tp_dealloc */
10481093
0, /* tp_vectorcall_offset */
10491094
0, /* tp_getattr */
10501095
0, /* tp_setattr */
10511096
0, /* tp_as_async */
1052-
0, /* tp_repr */
1097+
(reprfunc)mmap__repr__method, /* tp_repr */
10531098
0, /* tp_as_number */
1054-
&mmap_as_sequence, /*tp_as_sequence*/
1055-
&mmap_as_mapping, /*tp_as_mapping*/
1056-
0, /*tp_hash*/
1057-
0, /*tp_call*/
1058-
0, /*tp_str*/
1059-
PyObject_GenericGetAttr, /*tp_getattro*/
1060-
0, /*tp_setattro*/
1061-
&mmap_as_buffer, /*tp_as_buffer*/
1062-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1063-
mmap_doc, /*tp_doc*/
1099+
&mmap_as_sequence, /* tp_as_sequence */
1100+
&mmap_as_mapping, /* tp_as_mapping */
1101+
0, /* tp_hash */
1102+
0, /* tp_call */
1103+
0, /* tp_str */
1104+
PyObject_GenericGetAttr, /* tp_getattro */
1105+
0, /* tp_setattro */
1106+
&mmap_as_buffer, /* tp_as_buffer */
1107+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1108+
mmap_doc, /* tp_doc */
10641109
0, /* tp_traverse */
10651110
0, /* tp_clear */
10661111
0, /* tp_richcompare */

0 commit comments

Comments
 (0)