diff options
author | Taine Zhao <twshere@outlook.com> | 2019-10-17 10:41:35 (GMT) |
---|---|---|
committer | Xiang Zhang <angwerzx@126.com> | 2019-10-17 10:41:35 (GMT) |
commit | d8ca2354ed30c12b9ce37c4535222b700a727b32 (patch) | |
tree | 19976661fd0a220047cd06bbed695e9452c73eea | |
parent | 9c11029bb41caab5576f354fbf808a5e91325bb0 (diff) | |
download | cpython-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.py | 36 | ||||
-rw-r--r-- | Modules/mmapmodule.c | 69 |
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 */ |