aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George2020-07-25 23:05:41 +1000
committerDamien George2020-07-25 23:10:05 +1000
commit441460d81ff2b1faee7d044d859896f754361b93 (patch)
tree3c8b4205e9546dc6ddaa56f336e63a304e4e1218
parentfd2ff867a08fd174f0bbf7a03aa59547634e91ac (diff)
extmod/uasyncio: Add StreamReader.readexactly(n) method.
It raises on EOFError instead of an IncompleteReadError (which is what CPython does). But the latter is derived from EOFError so code compatible with MicroPython and CPython can be written by catching EOFError (eg see included test). Fixes issue #6156. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--extmod/uasyncio/stream.py12
-rw-r--r--tests/multi_net/uasyncio_tcp_readexactly.py68
-rw-r--r--tests/multi_net/uasyncio_tcp_readexactly.py.exp10
3 files changed, 90 insertions, 0 deletions
diff --git a/extmod/uasyncio/stream.py b/extmod/uasyncio/stream.py
index 2a1efd1a1..b6d787e4f 100644
--- a/extmod/uasyncio/stream.py
+++ b/extmod/uasyncio/stream.py
@@ -30,6 +30,18 @@ class Stream:
yield core._io_queue.queue_read(self.s)
return self.s.read(n)
+ async def readexactly(self, n):
+ r = b""
+ while n:
+ yield core._io_queue.queue_read(self.s)
+ r2 = self.s.read(n)
+ if r2 is not None:
+ if not len(r2):
+ raise EOFError
+ r += r2
+ n -= len(r2)
+ return r
+
async def readline(self):
l = b""
while True:
diff --git a/tests/multi_net/uasyncio_tcp_readexactly.py b/tests/multi_net/uasyncio_tcp_readexactly.py
new file mode 100644
index 000000000..71d8c6d0e
--- /dev/null
+++ b/tests/multi_net/uasyncio_tcp_readexactly.py
@@ -0,0 +1,68 @@
+# Test uasyncio stream readexactly() method using TCP server/client
+
+try:
+ import uasyncio as asyncio
+except ImportError:
+ try:
+ import asyncio
+ except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+PORT = 8000
+
+
+async def handle_connection(reader, writer):
+ writer.write(b"a")
+ await writer.drain()
+
+ # Split the first 2 bytes up so the client must wait for the second one
+ await asyncio.sleep(0.1)
+
+ writer.write(b"b")
+ await writer.drain()
+
+ writer.write(b"c")
+ await writer.drain()
+
+ writer.write(b"d")
+ await writer.drain()
+
+ print("close")
+ writer.close()
+ await writer.wait_closed()
+
+ print("done")
+ ev.set()
+
+
+async def tcp_server():
+ global ev
+ ev = asyncio.Event()
+ server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT)
+ print("server running")
+ multitest.next()
+ async with server:
+ await asyncio.wait_for(ev.wait(), 10)
+
+
+async def tcp_client():
+ reader, writer = await asyncio.open_connection(IP, PORT)
+ print(await reader.readexactly(2))
+ print(await reader.readexactly(0))
+ print(await reader.readexactly(1))
+ try:
+ print(await reader.readexactly(2))
+ except EOFError as er:
+ print("EOFError")
+ print(await reader.readexactly(0))
+
+
+def instance0():
+ multitest.globals(IP=multitest.get_network_ip())
+ asyncio.run(tcp_server())
+
+
+def instance1():
+ multitest.next()
+ asyncio.run(tcp_client())
diff --git a/tests/multi_net/uasyncio_tcp_readexactly.py.exp b/tests/multi_net/uasyncio_tcp_readexactly.py.exp
new file mode 100644
index 000000000..65ce6d628
--- /dev/null
+++ b/tests/multi_net/uasyncio_tcp_readexactly.py.exp
@@ -0,0 +1,10 @@
+--- instance0 ---
+server running
+close
+done
+--- instance1 ---
+b'ab'
+b''
+b'c'
+EOFError
+b''