Skip to content

Commit a5f0f6c

Browse files
committed
Address review: reword write() docs, share a test helper, fix NEWS role
1 parent 07641dc commit a5f0f6c

3 files changed

Lines changed: 16 additions & 23 deletions

File tree

‎Doc/library/asyncio-protocol.rst‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ Write-only Transports
333333
This method does not block; it buffers the data and arranges for it
334334
to be sent out asynchronously.
335335

336-
Do not modify *data* until it has been sent.
336+
The transport keeps a reference to *data* rather than copying. *data*
337+
must not be mutated while being sent.
337338

338339
.. method:: WriteTransport.writelines(list_of_data)
339340

‎Lib/test/test_asyncio/test_selector_events.py‎

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,16 @@ def socket_transport(self, waiter=None, sendmsg=False):
618618
self.addCleanup(close_transport, transport)
619619
return transport
620620

621+
def assert_remainder_is_view(self, transport, buf):
622+
# gh-159503: the unsent remainder is a view, not a copy
623+
rest = transport._buffer[0]
624+
self.assertIsInstance(rest, memoryview)
625+
self.assertIs(rest.obj, memoryview(buf).obj)
626+
if isinstance(buf, bytearray):
627+
# The unsent view pins the bytearray against resizing.
628+
with self.assertRaises(BufferError):
629+
buf.append(0)
630+
621631
def test_ctor(self):
622632
waiter = self.loop.create_future()
623633
tr = self.socket_transport(waiter=waiter)
@@ -972,16 +982,7 @@ def test_write_sendmsg_partial(self):
972982
self.assertTrue(self.sock.sendmsg.called)
973983
self.assertTrue(self.loop.writers)
974984
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
975-
# gh-159503: the remainder is a view, not a copy
976-
rest = transport._buffer[0]
977-
self.assertIsInstance(rest, memoryview)
978-
self.assertIs(
979-
rest.obj,
980-
buf.obj if isinstance(buf, memoryview) else buf)
981-
if isinstance(buf, bytearray):
982-
# The unsent view pins the bytearray against resizing.
983-
with self.assertRaises(BufferError):
984-
buf.append(0)
985+
self.assert_remainder_is_view(transport, buf)
985986

986987
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
987988
def test_write_sendmsg_half_buffer(self):
@@ -1093,16 +1094,7 @@ def test_write_ready_partial(self):
10931094
transport._write_ready()
10941095
self.loop.assert_writer(7, transport._write_ready)
10951096
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
1096-
# gh-159503: the remainder is a view, not a copy
1097-
rest = transport._buffer[0]
1098-
self.assertIsInstance(rest, memoryview)
1099-
self.assertIs(
1100-
rest.obj,
1101-
buf.obj if isinstance(buf, memoryview) else buf)
1102-
if isinstance(buf, bytearray):
1103-
# The unsent view pins the bytearray against resizing.
1104-
with self.assertRaises(BufferError):
1105-
buf.append(0)
1097+
self.assert_remainder_is_view(transport, buf)
11061098

11071099
def test_write_ready_partial_none(self):
11081100
data = b'data'
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Fix quadratic copying in :mod:`asyncio` selector socket transports on partial
2-
sends. A :class:`bytearray` passed to ``write()`` now stays locked against
3-
resizing until it has been sent.
2+
sends. A :class:`bytearray` passed to :meth:`~asyncio.WriteTransport.write`
3+
now stays locked against resizing until it has been sent.

0 commit comments

Comments
 (0)