bpo-34953: Implement mmap.mmap.__repr__ (GH-9891)

This commit is contained in:
Taine Zhao 2019-10-17 18:41:35 +08:00 committed by Xiang Zhang
parent 9c11029bb4
commit d8ca2354ed
2 changed files with 93 additions and 12 deletions

View file

@ -740,6 +740,42 @@ class MmapTests(unittest.TestCase):
# See bpo-34754 for details. # See bpo-34754 for details.
self.assertRaises(OSError, mm.flush, 1, len(b'python')) self.assertRaises(OSError, mm.flush, 1, len(b'python'))
def test_repr(self):
open_mmap_repr_pat = re.compile(
r"<mmap.mmap closed=False, "
r"access=(?P<access>\S+), "
r"length=(?P<length>\d+), "
r"pos=(?P<pos>\d+), "
r"offset=(?P<offset>\d+)>")
closed_mmap_repr_pat = re.compile(r"<mmap.mmap closed=True>")
mapsizes = (50, 100, 1_000, 1_000_000, 10_000_000)
offsets = tuple((mapsize // 2 // mmap.ALLOCATIONGRANULARITY)
* mmap.ALLOCATIONGRANULARITY for mapsize in mapsizes)
for offset, mapsize in zip(offsets, mapsizes):
data = b'a' * mapsize
length = mapsize - offset
accesses = ('ACCESS_DEFAULT', 'ACCESS_READ',
'ACCESS_COPY', 'ACCESS_WRITE')
positions = (0, length//10, length//5, length//4)
with open(TESTFN, "wb+") as fp:
fp.write(data)
fp.flush()
for access, pos in itertools.product(accesses, positions):
accint = getattr(mmap, access)
with mmap.mmap(fp.fileno(),
length,
access=accint,
offset=offset) as mm:
mm.seek(pos)
match = open_mmap_repr_pat.match(repr(mm))
self.assertIsNotNone(match)
self.assertEqual(match.group('access'), access)
self.assertEqual(match.group('length'), str(length))
self.assertEqual(match.group('pos'), str(pos))
self.assertEqual(match.group('offset'), str(offset))
match = closed_mmap_repr_pat.match(repr(mm))
self.assertIsNotNone(match)
@unittest.skipUnless(hasattr(mmap.mmap, 'madvise'), 'needs madvise') @unittest.skipUnless(hasattr(mmap.mmap, 'madvise'), 'needs madvise')
def test_madvise(self): def test_madvise(self):
size = 2 * PAGESIZE size = 2 * PAGESIZE

View file

@ -695,6 +695,51 @@ mmap__exit__method(PyObject *self, PyObject *args)
return _PyObject_CallMethodIdNoArgs(self, &PyId_close); return _PyObject_CallMethodIdNoArgs(self, &PyId_close);
} }
static PyObject *
mmap__repr__method(PyObject *self)
{
mmap_object *mobj = (mmap_object *)self;
#ifdef MS_WINDOWS
#define _Py_FORMAT_OFFSET "lld"
if (mobj->map_handle == NULL)
#elif defined(UNIX)
# ifdef HAVE_LARGEFILE_SUPPORT
# define _Py_FORMAT_OFFSET "lld"
# else
# define _Py_FORMAT_OFFSET "ld"
# endif
if (mobj->data == NULL)
#endif
{
return PyUnicode_FromFormat("<%s closed=True>", Py_TYPE(self)->tp_name);
} else {
const char *access_str;
switch (mobj->access) {
case ACCESS_DEFAULT:
access_str = "ACCESS_DEFAULT";
break;
case ACCESS_READ:
access_str = "ACCESS_READ";
break;
case ACCESS_WRITE:
access_str = "ACCESS_WRITE";
break;
case ACCESS_COPY:
access_str = "ACCESS_COPY";
break;
default:
Py_UNREACHABLE();
}
return PyUnicode_FromFormat("<%s closed=False, access=%s, length=%zd, "
"pos=%zd, offset=%" _Py_FORMAT_OFFSET ">",
Py_TYPE(self)->tp_name, access_str,
mobj->size, mobj->pos, mobj->offset);
}
}
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
static PyObject * static PyObject *
mmap__sizeof__method(mmap_object *self, void *unused) mmap__sizeof__method(mmap_object *self, void *unused)
@ -1049,7 +1094,7 @@ static PyTypeObject mmap_object_type = {
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
0, /* tp_repr */ (reprfunc)mmap__repr__method, /* tp_repr */
0, /* tp_as_number */ 0, /* tp_as_number */
&mmap_as_sequence, /* tp_as_sequence */ &mmap_as_sequence, /* tp_as_sequence */
&mmap_as_mapping, /* tp_as_mapping */ &mmap_as_mapping, /* tp_as_mapping */