# we got end-of-file so no need to reschedule a new read
return
- data = self._data[:length]
+ # It's a new slice so make it immutable so protocols upstream don't have problems
+ data = bytes(memoryview(self._data)[:length])
else:
# the future will be replaced by next proactor.recv call
fut.cancel()
await self._wait_for_data('read')
# This will work right even if buffer is less than n bytes
- data = bytes(self._buffer[:n])
+ data = bytes(memoryview(self._buffer)[:n])
del self._buffer[:n]
self._maybe_resume_transport()
data = bytes(self._buffer)
self._buffer.clear()
else:
- data = bytes(self._buffer[:n])
+ data = bytes(memoryview(self._buffer)[:n])
del self._buffer[:n]
self._maybe_resume_transport()
return data
called_buf = bytearray(self.buffer_size)
called_buf[:len(buf)] = buf
self.loop._proactor.recv_into.assert_called_with(self.sock, called_buf)
- self.protocol.data_received.assert_called_with(bytearray(buf))
+ self.protocol.data_received.assert_called_with(buf)
+ # assert_called_with maps bytearray and bytes to the same thing so check manually
+ # regression test for https://github.com/python/cpython/issues/99941
+ self.assertIsInstance(self.protocol.data_received.call_args.args[0], bytes)
@unittest.skipIf(sys.flags.optimize, "Assertions are disabled in optimized mode")
def test_loop_reading_no_data(self):
--- /dev/null
+Ensure that :func:`asyncio.Protocol.data_received` receives an immutable
+:class:`bytes` object (as documented), instead of :class:`bytearray`.