if isinstance(b, str):
raise TypeError("can't write str to binary stream")
with memoryview(b) as view:
- n = view.nbytes # Size of any bytes-like object
if self.closed:
raise ValueError("write to closed file")
- if n == 0:
- return 0
- pos = self._pos
- if pos > len(self._buffer):
- # Inserts null bytes between the current end of the file
- # and the new write position.
- padding = b'\x00' * (pos - len(self._buffer))
- self._buffer += padding
- self._buffer[pos:pos + n] = b
- self._pos += n
+
+ n = view.nbytes # Size of any bytes-like object
+ if n == 0:
+ return 0
+
+ pos = self._pos
+ if pos > len(self._buffer):
+ # Inserts null bytes between the current end of the file
+ # and the new write position.
+ padding = b'\x00' * (pos - len(self._buffer))
+ self._buffer += padding
+ self._buffer[pos:pos + n] = view
+ self._pos += n
return n
def seek(self, pos, whence=0):
memio = self.ioclass()
self.assertRaises(BufferError, memio.writelines, [B()])
+ def test_write_mutating_buffer(self):
+ # Test that buffer is exported only once during write().
+ # See: https://github.com/python/cpython/issues/143602.
+ class B:
+ count = 0
+ def __buffer__(self, flags):
+ self.count += 1
+ if self.count == 1:
+ return memoryview(b"AAA")
+ else:
+ return memoryview(b"BBBBBBBBB")
+
+ memio = self.ioclass(b'0123456789')
+ memio.seek(2)
+ b = B()
+ n = memio.write(b)
+
+ self.assertEqual(b.count, 1)
+ self.assertEqual(n, 3)
+ self.assertEqual(memio.getvalue(), b"01AAA56789")
+ self.assertEqual(memio.tell(), 5)
+
class TextIOTestMixin: