diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 2d4bf5f1408df8..bada5af3b2458e 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -64,6 +64,24 @@ def test_iter(self): m = self._view(b) self.assertEqual(list(m), [m[i] for i in range(len(m))]) + def test_contains(self): + for tp in self._types: + b = tp(self._source) + m = self._view(b) + for c in list(m): + with self.subTest(self._source, buffer_type=tp, item=c): + self.assertIn(c, m) + + with self.subTest('empty buffer'): + empty = tp(b'') + mview = self._view(empty) + self.assertNotIn(0, mview) + + with self.subTest('not found'): + b = tp(b'abc') + m = self._view(b) + self.assertNotIn(ord('d'), m) + def test_setitem_readonly(self): if not self.ro_type: self.skipTest("no read-only type to test") diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-14-12-17-00.gh-issue-125420.hpMz9A.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-14-12-17-00.gh-issue-125420.hpMz9A.rst new file mode 100644 index 00000000000000..66b8a04498faf2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-14-12-17-00.gh-issue-125420.hpMz9A.rst @@ -0,0 +1,2 @@ +Implement :meth:`~object.__contains__` for :class:`memoryview` objects. +Patch by Bénédikt Tran. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index a2472d4873641d..1eb45a950aabca 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -2483,6 +2483,37 @@ memory_item_multi(PyMemoryViewObject *self, PyObject *tup) return unpack_single(self, ptr, fmt); } +/* Test the membership of an item. */ +static int +memory_contains(PyObject *self, PyObject *value) +{ + PyObject *iter = PyObject_GetIter(self); + if (iter == NULL) { + return -1; + } + + PyObject *item = NULL; + while (PyIter_NextItem(iter, &item)) { + if (item == NULL) { + Py_DECREF(iter); + return -1; + } + if (item == value) { + Py_DECREF(item); + Py_DECREF(iter); + return 1; + } + int contained = PyObject_RichCompareBool(item, value, Py_EQ); + Py_DECREF(item); + if (contained != 0) { + Py_DECREF(iter); + return contained; + } + } + Py_DECREF(iter); + return 0; +} + static inline int init_slice(Py_buffer *base, PyObject *key, int dim) { @@ -2741,10 +2772,9 @@ static PyMappingMethods memory_as_mapping = { /* As sequence */ static PySequenceMethods memory_as_sequence = { - memory_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - memory_item, /* sq_item */ + .sq_length = memory_length, + .sq_item = memory_item, + .sq_contains = memory_contains };