Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 11194c8

Browse files
authored
bpo-34666: Implement stream.awrite() and stream.aclose() (GH-9274)
1 parent 413118e commit 11194c8

4 files changed

Lines changed: 79 additions & 22 deletions

File tree

Doc/library/asyncio-stream.rst

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ streams::
2020
'127.0.0.1', 8888)
2121

2222
print(f'Send: {message!r}')
23-
writer.write(message.encode())
23+
await writer.awrite(message.encode())
2424

2525
data = await reader.read(100)
2626
print(f'Received: {data.decode()!r}')
2727

2828
print('Close the connection')
29-
writer.close()
29+
await writer.aclose()
3030

3131
asyncio.run(tcp_echo_client('Hello World!'))
3232

@@ -229,14 +229,57 @@ StreamWriter
229229
directly; use :func:`open_connection` and :func:`start_server`
230230
instead.
231231

232+
.. coroutinemethod:: awrite(data)
233+
234+
Write *data* to the stream.
235+
236+
The method respects control-flow, execution is paused if write
237+
buffer reaches high-water limit.
238+
239+
.. versionadded:: 3.8
240+
241+
.. coroutinemethod:: aclose()
242+
243+
Close the stream.
244+
245+
Wait for finishing all closing actions, e.g. SSL shutdown for
246+
secure sockets.
247+
248+
.. versionadded:: 3.8
249+
250+
.. method:: can_write_eof()
251+
252+
Return *True* if the underlying transport supports
253+
the :meth:`write_eof` method, *False* otherwise.
254+
255+
.. method:: write_eof()
256+
257+
Close the write end of the stream after the buffered write
258+
data is flushed.
259+
260+
.. attribute:: transport
261+
262+
Return the underlying asyncio transport.
263+
264+
.. method:: get_extra_info(name, default=None)
265+
266+
Access optional transport information; see
267+
:meth:`BaseTransport.get_extra_info` for details.
268+
232269
.. method:: write(data)
233270

234271
Write *data* to the stream.
235272

273+
This method doesn't apply control-flow. The call should be
274+
followed by :meth:`drain`.
275+
236276
.. method:: writelines(data)
237277

238278
Write a list (or any iterable) of bytes to the stream.
239279

280+
This method doesn't apply control-flow. The call should be
281+
followed by :meth:`drain`.
282+
240283
.. coroutinemethod:: drain()
241284

242285
Wait until it is appropriate to resume writing to the stream.
@@ -272,25 +315,6 @@ StreamWriter
272315

273316
.. versionadded:: 3.7
274317

275-
.. method:: can_write_eof()
276-
277-
Return *True* if the underlying transport supports
278-
the :meth:`write_eof` method, *False* otherwise.
279-
280-
.. method:: write_eof()
281-
282-
Close the write end of the stream after the buffered write
283-
data is flushed.
284-
285-
.. attribute:: transport
286-
287-
Return the underlying asyncio transport.
288-
289-
.. method:: get_extra_info(name, default=None)
290-
291-
Access optional transport information; see
292-
:meth:`BaseTransport.get_extra_info` for details.
293-
294318

295319
Examples
296320
========

Lib/asyncio/streams.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ def close(self):
348348
# a reader can be garbage collected
349349
# after connection closing
350350
self._protocol._untrack_reader()
351-
return self._transport.close()
351+
self._transport.close()
352352

353353
def is_closing(self):
354354
return self._transport.is_closing()
@@ -381,6 +381,14 @@ async def drain(self):
381381
await sleep(0, loop=self._loop)
382382
await self._protocol._drain_helper()
383383

384+
async def aclose(self):
385+
self.close()
386+
await self.wait_closed()
387+
388+
async def awrite(self, data):
389+
self.write(data)
390+
await self.drain()
391+
384392

385393
class StreamReader:
386394

Lib/test/test_asyncio/test_streams.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,28 @@ def test_del_stream_before_connection_made(self):
964964
'call "stream.close()" explicitly.',
965965
messages[0]['message'])
966966

967+
def test_async_writer_api(self):
968+
messages = []
969+
self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
970+
971+
with test_utils.run_test_server() as httpd:
972+
rd, wr = self.loop.run_until_complete(
973+
asyncio.open_connection(*httpd.address,
974+
loop=self.loop))
975+
976+
f = wr.awrite(b'GET / HTTP/1.0\r\n\r\n')
977+
self.loop.run_until_complete(f)
978+
f = rd.readline()
979+
data = self.loop.run_until_complete(f)
980+
self.assertEqual(data, b'HTTP/1.0 200 OK\r\n')
981+
f = rd.read()
982+
data = self.loop.run_until_complete(f)
983+
self.assertTrue(data.endswith(b'\r\n\r\nTest message'))
984+
f = wr.aclose()
985+
self.loop.run_until_complete(f)
986+
987+
self.assertEqual(messages, [])
988+
967989

968990
if __name__ == '__main__':
969991
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Implement ``asyncio.StreamWriter.awrite`` and
2+
``asyncio.StreamWriter.aclose()`` coroutines. Methods are needed for
3+
providing a consistent stream API with control flow switched on by default.

0 commit comments

Comments
 (0)