Skip to content

Commit 12de092

Browse files
committed
Fold the new checks into the existing partial-write tests
Address review: test_write_ready_partial and test_write_sendmsg_partial now run for both bytes and memoryview input and check that the remainder is a view on the original object. Wrap the NEWS entry at 78 columns.
1 parent 0ee8476 commit 12de092

2 files changed

Lines changed: 31 additions & 51 deletions

File tree

‎Lib/test/test_asyncio/test_selector_events.py‎

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -958,35 +958,22 @@ def test_write_sendmsg_full(self):
958958

959959
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
960960
def test_write_sendmsg_partial(self):
961-
962-
data = memoryview(b'data')
963-
self.sock.sendmsg = mock.Mock()
964-
# Sent partial data
965-
self.sock.sendmsg.return_value = 2
966-
967-
transport = self.socket_transport(sendmsg=True)
968-
transport._buffer.append(data)
969-
self.loop._add_writer(7, transport._write_ready)
970-
transport._write_ready()
971-
self.assertTrue(self.sock.sendmsg.called)
972-
self.assertTrue(self.loop.writers)
973-
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
974-
975-
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
976-
def test_write_sendmsg_partial_bytes_no_copy(self):
977-
# gh-159503: the unsent remainder of a bytes object must not be
978-
# copied, otherwise a large write costs O(n**2).
979961
data = b'data'
980-
self.sock.sendmsg = mock.Mock()
981-
self.sock.sendmsg.return_value = 2
982-
983-
transport = self.socket_transport(sendmsg=True)
984-
transport._buffer.append(data)
985-
self.loop._add_writer(7, transport._write_ready)
986-
transport._write_ready()
987-
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
988-
self.assertIsInstance(transport._buffer[0], memoryview)
989-
self.assertIs(transport._buffer[0].obj, data)
962+
for buf in data, memoryview(data):
963+
with self.subTest(type=type(buf).__name__):
964+
self.sock.sendmsg = mock.Mock()
965+
# Sent partial data
966+
self.sock.sendmsg.return_value = 2
967+
968+
transport = self.socket_transport(sendmsg=True)
969+
transport._buffer.append(buf)
970+
self.loop._add_writer(7, transport._write_ready)
971+
transport._write_ready()
972+
self.assertTrue(self.sock.sendmsg.called)
973+
self.assertTrue(self.loop.writers)
974+
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
975+
# gh-159503: the remainder is a view, not a copy
976+
self.assertIs(transport._buffer[0].obj, data)
990977

991978
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
992979
def test_write_sendmsg_half_buffer(self):
@@ -1087,29 +1074,19 @@ def test_write_ready_no_data(self):
10871074
self.assertRaises(AssertionError, transport._write_ready)
10881075

10891076
def test_write_ready_partial(self):
1090-
data = memoryview(b'data')
1091-
self.sock.send.return_value = 2
1092-
1093-
transport = self.socket_transport()
1094-
transport._buffer.append(data)
1095-
self.loop._add_writer(7, transport._write_ready)
1096-
transport._write_ready()
1097-
self.loop.assert_writer(7, transport._write_ready)
1098-
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
1099-
1100-
def test_write_ready_partial_bytes_no_copy(self):
1101-
# gh-159503: the unsent remainder of a bytes object must not be
1102-
# copied, otherwise a large write costs O(n**2).
11031077
data = b'data'
1104-
self.sock.send.return_value = 2
1105-
1106-
transport = self.socket_transport()
1107-
transport._buffer.append(data)
1108-
self.loop._add_writer(7, transport._write_ready)
1109-
transport._write_ready()
1110-
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
1111-
self.assertIsInstance(transport._buffer[0], memoryview)
1112-
self.assertIs(transport._buffer[0].obj, data)
1078+
for buf in data, memoryview(data):
1079+
with self.subTest(type=type(buf).__name__):
1080+
self.sock.send.return_value = 2
1081+
1082+
transport = self.socket_transport()
1083+
transport._buffer.append(buf)
1084+
self.loop._add_writer(7, transport._write_ready)
1085+
transport._write_ready()
1086+
self.loop.assert_writer(7, transport._write_ready)
1087+
self.assertEqual(list_to_buffer([b'ta']), transport._buffer)
1088+
# gh-159503: the remainder is a view, not a copy
1089+
self.assertIs(transport._buffer[0].obj, data)
11131090

11141091
def test_write_ready_partial_none(self):
11151092
data = b'data'
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
Fix quadratic copying in :mod:`asyncio` selector socket transports when a large :class:`bytes` write is only partly sent while other data is buffered. The unsent remainder is now kept as a :class:`memoryview` instead of being copied on every partial send.
1+
Fix quadratic copying in :mod:`asyncio` selector socket transports when a
2+
large :class:`bytes` write is only partly sent while other data is buffered.
3+
The unsent remainder is now kept as a :class:`memoryview` instead of being
4+
copied on every partial send.

0 commit comments

Comments
 (0)