diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -291,6 +291,22 @@ self.assertEqual(self.type2test(b".").join([b"ab", b"cd"]), b"ab.cd") # XXX more... + + def test_join_with_memoryviews(self): + # see issue #15958 + if self.type2test is bytearray: + self.skipTest("join w/ memoryview not implemented yet") + sep1, sep2 = self.type2test(b''), self.type2test(b'-') + mfoo, mbar = memoryview(b'foo'), memoryview(b'bar') + bfoo, bbar = self.type2test(b'foo'), self.type2test(b'bar') + self.assertEqual(sep1.join([mfoo]), bfoo) + self.assertEqual(sep1.join([mfoo, bbar]), b'foobar') + self.assertEqual(sep1.join([bfoo, mbar]), b'foobar') + self.assertEqual(sep1.join([mfoo, mbar]), b'foobar') + self.assertEqual(sep2.join([mfoo, mbar]), b'foo-bar') + self.assertEqual(sep2.join([mfoo, bbar, mfoo]), b'foo-bar-foo') + + def test_count(self): b = self.type2test(b'mississippi') i = 105 diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1146,15 +1146,19 @@ for (i = 0; i < seqlen; i++) { const size_t old_sz = sz; item = PySequence_Fast_GET_ITEM(seq, i); - if (!PyBytes_Check(item) && !PyByteArray_Check(item)) { + if (!PyBytes_Check(item) && !PyByteArray_Check(item) && + !PyMemoryView_Check(item)) { PyErr_Format(PyExc_TypeError, - "sequence item %zd: expected bytes," - " %.80s found", + "sequence item %zd: expected bytes, bytearray, " + "or memoryview, %.80s found", i, Py_TYPE(item)->tp_name); Py_DECREF(seq); return NULL; } - sz += Py_SIZE(item); + if (PyMemoryView_Check(item)) + sz += PyMemoryView_GET_BUFFER(item)->len; + else + sz += Py_SIZE(item); if (i != 0) sz += seplen; if (sz < old_sz || sz > PY_SSIZE_T_MAX) { @@ -1184,11 +1188,18 @@ p += seplen; } item = PySequence_Fast_GET_ITEM(seq, i); - n = Py_SIZE(item); - if (PyBytes_Check(item)) + if (PyBytes_Check(item)) { + n = Py_SIZE(item); q = PyBytes_AS_STRING(item); - else + else if (PyByteArray_Check(item)) { + n = Py_SIZE(item); q = PyByteArray_AS_STRING(item); + } + else { + Py_buffer *view = PyMemoryView_GET_BUFFER(item); + n = view->len; + q = view->buf; + } Py_MEMCPY(p, q, n); p += n; }