Skip to content

Commit 67d6bed

Browse files
Allow DatagramTransport.sendto to send empty data
1 parent 1a10437 commit 67d6bed

File tree

7 files changed

+40
-14
lines changed

7 files changed

+40
-14
lines changed

Doc/library/asyncio-protocol.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ Datagram Transports
362362
This method does not block; it buffers the data and arranges
363363
for it to be sent out asynchronously.
364364

365+
.. versionchanged:: 3.13
366+
This method can be called with an empty bytes object to send a
367+
zero-length datagram.
368+
365369
.. method:: DatagramTransport.abort()
366370

367371
Close the transport immediately, without waiting for pending

Lib/asyncio/proactor_events.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,6 @@ def sendto(self, data, addr=None):
487487
raise TypeError('data argument must be bytes-like object (%r)',
488488
type(data))
489489

490-
if not data:
491-
return
492-
493490
if self._address is not None and addr not in (None, self._address):
494491
raise ValueError(
495492
f'Invalid address: must be None or {self._address}')

Lib/asyncio/selector_events.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,8 +1241,6 @@ def sendto(self, data, addr=None):
12411241
if not isinstance(data, (bytes, bytearray, memoryview)):
12421242
raise TypeError(f'data argument must be a bytes-like object, '
12431243
f'not {type(data).__name__!r}')
1244-
if not data:
1245-
return
12461244

12471245
if self._address:
12481246
if addr not in (None, self._address):

Lib/asyncio/transports.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ def sendto(self, data, addr=None):
181181
to be sent out asynchronously.
182182
addr is target socket address.
183183
If addr is None use target address pointed on transport creation.
184+
If data is an empty bytes object a zero-length datagram will be
185+
sent.
184186
"""
185187
raise NotImplementedError
186188

Lib/test/test_asyncio/test_proactor_events.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -585,11 +585,10 @@ def test_sendto_memoryview(self):
585585

586586
def test_sendto_no_data(self):
587587
transport = self.datagram_transport()
588-
transport._buffer.append((b'data', ('0.0.0.0', 12345)))
589-
transport.sendto(b'', ())
590-
self.assertFalse(self.sock.sendto.called)
591-
self.assertEqual(
592-
[(b'data', ('0.0.0.0', 12345))], list(transport._buffer))
588+
transport.sendto(b'', ('0.0.0.0', 1234))
589+
self.assertTrue(self.proactor.sendto.called)
590+
self.proactor.sendto.assert_called_with(
591+
self.sock, b'', addr=('0.0.0.0', 1234))
593592

594593
def test_sendto_buffer(self):
595594
transport = self.datagram_transport()
@@ -628,6 +627,19 @@ def test_sendto_buffer_memoryview(self):
628627
list(transport._buffer))
629628
self.assertIsInstance(transport._buffer[1][0], bytes)
630629

630+
def test_sendto_buffer_nodata(self):
631+
data2 = b''
632+
transport = self.datagram_transport()
633+
transport._buffer.append((b'data1', ('0.0.0.0', 12345)))
634+
transport._write_fut = object()
635+
transport.sendto(data2, ('0.0.0.0', 12345))
636+
self.assertFalse(self.proactor.sendto.called)
637+
self.assertEqual(
638+
[(b'data1', ('0.0.0.0', 12345)),
639+
(b'', ('0.0.0.0', 12345))],
640+
list(transport._buffer))
641+
self.assertIsInstance(transport._buffer[1][0], bytes)
642+
631643
@mock.patch('asyncio.proactor_events.logger')
632644
def test_sendto_exception(self, m_log):
633645
data = b'data'

Lib/test/test_asyncio/test_selector_events.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,11 +1280,10 @@ def test_sendto_memoryview(self):
12801280

12811281
def test_sendto_no_data(self):
12821282
transport = self.datagram_transport()
1283-
transport._buffer.append((b'data', ('0.0.0.0', 12345)))
1284-
transport.sendto(b'', ())
1285-
self.assertFalse(self.sock.sendto.called)
1283+
transport.sendto(b'', ('0.0.0.0', 1234))
1284+
self.assertTrue(self.sock.sendto.called)
12861285
self.assertEqual(
1287-
[(b'data', ('0.0.0.0', 12345))], list(transport._buffer))
1286+
self.sock.sendto.call_args[0], (b'', ('0.0.0.0', 1234)))
12881287

12891288
def test_sendto_buffer(self):
12901289
transport = self.datagram_transport()
@@ -1320,6 +1319,18 @@ def test_sendto_buffer_memoryview(self):
13201319
list(transport._buffer))
13211320
self.assertIsInstance(transport._buffer[1][0], bytes)
13221321

1322+
def test_sendto_buffer_nodata(self):
1323+
data2 = b''
1324+
transport = self.datagram_transport()
1325+
transport._buffer.append((b'data1', ('0.0.0.0', 12345)))
1326+
transport.sendto(data2, ('0.0.0.0', 12345))
1327+
self.assertFalse(self.sock.sendto.called)
1328+
self.assertEqual(
1329+
[(b'data1', ('0.0.0.0', 12345)),
1330+
(b'', ('0.0.0.0', 12345))],
1331+
list(transport._buffer))
1332+
self.assertIsInstance(transport._buffer[1][0], bytes)
1333+
13231334
def test_sendto_tryagain(self):
13241335
data = b'data'
13251336

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:meth:`DatagramTransport.sendto` will now send zero-length datagrams if
2+
called with an empty bytes object.

0 commit comments

Comments
 (0)