Skip to content

Commit 35c671f

Browse files
committed
micropython/streampair: Use RingIO and add async tests.
- Replace deprecated ringbuffer with RingIO name. - Remove unused collections.deque import. - Add test_select_poll_compatibility() to verify select.poll(). - Add test_streamreader_direct_usage() for asyncio.StreamReader. The existing ioctl implementation correctly returns -1 for unsupported operations, enabling select.poll() to work with pure Python stream objects. Since asyncio.StreamReader is built on select.poll(), StreamPair works seamlessly with async I/O. These tests document that Python objects with proper ioctl() implementation work with micropython polling and async infrastructure without requiring C-level integration. Signed-off-by: Andrew Leech <[email protected]> Signed-off-by: Andrew Leech <[email protected]>
1 parent 9e7db99 commit 35c671f

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

micropython/streampair/streampair.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import io
22

3-
from collections import deque
4-
from micropython import ringbuffer, const
3+
from micropython import RingIO, const
54

65
try:
76
from typing import Union, Tuple
@@ -28,14 +27,14 @@ def streampair(buffer_size: Union[int, Tuple[int, int]]=256):
2827
except TypeError:
2928
size_a = size_b = buffer_size
3029

31-
a = ringbuffer(size_a)
32-
b = ringbuffer(size_b)
30+
a = RingIO(size_a)
31+
b = RingIO(size_b)
3332
return StreamPair(a, b), StreamPair(b, a)
3433

3534

3635
class StreamPair(io.IOBase):
3736

38-
def __init__(self, own: ringbuffer, other: ringbuffer):
37+
def __init__(self, own: RingIO, other: RingIO):
3938
self.own = own
4039
self.other = other
4140
super().__init__()

micropython/streampair/test_streampair.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import unittest
3+
import select
34
from streampair import streampair
45

56
def async_test(f):
@@ -14,8 +15,8 @@ def wrapper(*args, **kwargs):
1415

1516
return wrapper
1617

17-
class StreamPairTestCase(unittest.TestCase):
1818

19+
class StreamPairTestCase(unittest.TestCase):
1920
def test_streampair(self):
2021
a, b = streampair()
2122
assert a.write(b"foo") == 3
@@ -49,6 +50,59 @@ async def test_async_streampair(self):
4950
assert not b.any()
5051
assert not a.any()
5152

53+
def test_select_poll_compatibility(self):
54+
"""Test that streampair works with select.poll()"""
55+
a, b = streampair()
56+
57+
# Register stream with poll
58+
poller = select.poll()
59+
poller.register(a, select.POLLIN)
60+
61+
# No data available initially
62+
events = poller.poll(0)
63+
assert len(events) == 0, f"Expected no events, got {events}"
64+
65+
# Write data to b, should be readable from a
66+
b.write(b"test data")
67+
68+
# Should now poll as readable
69+
events = poller.poll(0)
70+
assert len(events) == 1, f"Expected 1 event, got {events}"
71+
assert events[0][0] == a, "Event should be for stream a"
72+
assert events[0][1] & select.POLLIN, "Should be readable"
73+
74+
# Read the data
75+
data = a.read()
76+
assert data == b"test data", f"Expected b'test data', got {data}"
77+
78+
# Should no longer poll as readable
79+
events = poller.poll(0)
80+
assert len(events) == 0, f"Expected no events after read, got {events}"
81+
82+
poller.unregister(a)
83+
84+
@async_test
85+
async def test_streamreader_direct_usage(self):
86+
"""Test that streampair can be used directly with asyncio.StreamReader"""
87+
a, b = streampair()
88+
89+
# Create StreamReader directly on the streampair object
90+
reader = asyncio.StreamReader(a)
91+
92+
# Write data in background task
93+
async def write_delayed():
94+
await asyncio.sleep_ms(10)
95+
b.write(b"async test\n")
96+
97+
task = asyncio.create_task(write_delayed())
98+
99+
# Should be able to read via StreamReader
100+
data = await asyncio.wait_for(reader.readline(), 1.0)
101+
assert data == b"async test\n", f"Expected b'async test\\n', got {data}"
102+
103+
# Wait for background task to complete
104+
await task
105+
52106

53107
if __name__ == "__main__":
54108
unittest.main()

0 commit comments

Comments
 (0)