summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaine Zhao <twshere@outlook.com>2019-10-17 10:41:35 (GMT)
committerXiang Zhang <angwerzx@126.com>2019-10-17 10:41:35 (GMT)
commitd8ca2354ed30c12b9ce37c4535222b700a727b32 (patch)
tree19976661fd0a220047cd06bbed695e9452c73eea
parent9c11029bb41caab5576f354fbf808a5e91325bb0 (diff)
downloadcpython-d8ca2354ed30c12b9ce37c4535222b700a727b32.zip
cpython-d8ca2354ed30c12b9ce37c4535222b700a727b32.tar.gz
cpython-d8ca2354ed30c12b9ce37c4535222b700a727b32.tar.bz2
bpo-34953: Implement `mmap.mmap.__repr__` (GH-9891)
-rw-r--r--Lib/test/test_mmap.py36
-rw-r--r--Modules/mmapmodule.c69
2 files changed, 93 insertions, 12 deletions
diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
index 88c501d..5400f25 100644
--- a/Lib/test/test_mmap.py
+++ b/Lib/test/test_mmap.py
@@ -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
diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c
index 0c64163..a3b9e4d 100644
--- a/Modules/mmapmodule.c
+++ b/Modules/mmapmodule.c
@@ -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 */