Skip to content

Commit db7682e

Browse files
committed
extmod/uasyncio: Implement stream read(-1) to read all data up to EOF.
Fixes issue micropython#6355. Signed-off-by: Damien George <damien@micropython.org>
1 parent 2a25897 commit db7682e

File tree

4 files changed

+83
-5
lines changed

4 files changed

+83
-5
lines changed

docs/library/uasyncio.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,11 @@ TCP stream connections
237237

238238
This is a coroutine.
239239

240-
.. method:: Stream.read(n)
240+
.. method:: Stream.read(n=-1)
241241

242-
Read up to *n* bytes and return them.
242+
Read up to *n* bytes and return them. If *n* is not provided or -1 then read all
243+
bytes until EOF. The returned value will be an empty bytes object if EOF is
244+
encountered before any bytes are read.
243245

244246
This is a coroutine.
245247

extmod/uasyncio/stream.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,17 @@ async def wait_closed(self):
2626
# TODO yield?
2727
self.s.close()
2828

29-
async def read(self, n):
30-
yield core._io_queue.queue_read(self.s)
31-
return self.s.read(n)
29+
async def read(self, n=-1):
30+
r = b""
31+
while True:
32+
yield core._io_queue.queue_read(self.s)
33+
r2 = self.s.read(n)
34+
if r2 is not None:
35+
if n >= 0:
36+
return r2
37+
if not len(r2):
38+
return r
39+
r += r2
3240

3341
async def readinto(self, buf):
3442
yield core._io_queue.queue_read(self.s)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Test uasyncio stream read(-1) method using TCP server/client
2+
3+
try:
4+
import uasyncio as asyncio
5+
except ImportError:
6+
try:
7+
import asyncio
8+
except ImportError:
9+
print("SKIP")
10+
raise SystemExit
11+
12+
PORT = 8000
13+
14+
15+
async def handle_connection(reader, writer):
16+
writer.write(b"a")
17+
await writer.drain()
18+
19+
# Split the first 2 bytes up so the client must wait for the second one
20+
await asyncio.sleep(0.1)
21+
22+
writer.write(b"b")
23+
await writer.drain()
24+
25+
writer.write(b"c")
26+
await writer.drain()
27+
28+
print("close")
29+
writer.close()
30+
await writer.wait_closed()
31+
32+
print("done")
33+
ev.set()
34+
35+
36+
async def tcp_server():
37+
global ev
38+
ev = asyncio.Event()
39+
server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT)
40+
print("server running")
41+
multitest.next()
42+
async with server:
43+
await asyncio.wait_for(ev.wait(), 2)
44+
45+
46+
async def tcp_client():
47+
reader, writer = await asyncio.open_connection(IP, PORT)
48+
print(await reader.read())
49+
print(await reader.read()) # should be empty
50+
print(await reader.read(1)) # should be empty
51+
52+
53+
def instance0():
54+
multitest.globals(IP=multitest.get_network_ip())
55+
asyncio.run(tcp_server())
56+
57+
58+
def instance1():
59+
multitest.next()
60+
asyncio.run(tcp_client())
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
--- instance0 ---
2+
server running
3+
close
4+
done
5+
--- instance1 ---
6+
b'abc'
7+
b''
8+
b''

0 commit comments

Comments
 (0)