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.
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')
def test_madvise(self):
size = 2 * PAGESIZE

View File

@ -695,6 +695,51 @@ mmap__exit__method(PyObject *self, PyObject *args)
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
static PyObject *
mmap__sizeof__method(mmap_object *self, void *unused)
@ -1044,23 +1089,23 @@ static PyTypeObject mmap_object_type = {
sizeof(mmap_object), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor) mmap_object_dealloc, /* tp_dealloc */
(destructor)mmap_object_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
(reprfunc)mmap__repr__method, /* tp_repr */
0, /* tp_as_number */
&mmap_as_sequence, /*tp_as_sequence*/
&mmap_as_mapping, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
PyObject_GenericGetAttr, /*tp_getattro*/
0, /*tp_setattro*/
&mmap_as_buffer, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
mmap_doc, /*tp_doc*/
&mmap_as_sequence, /* tp_as_sequence */
&mmap_as_mapping, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
&mmap_as_buffer, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
mmap_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */