Skip to content

Commit 47badae

Browse files
committed
Updated StdioServer to use binary streams for stdin/stdout and added subprocess-based test for framed JSON-RPC communication
1 parent 7181b62 commit 47badae

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

lf_toolkit/io/stdio_server.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ class StdioClient(StreamIO):
1616

1717
def __init__(self):
1818
self.stream = StapledByteStream(
19-
FileWriteStream(sys.stdout),
20-
FileReadStream(sys.stdin),
19+
FileWriteStream(sys.stdout.buffer),
20+
FileReadStream(sys.stdin.buffer),
2121
)
2222

2323
async def read(self, size: int) -> bytes:
@@ -43,5 +43,6 @@ def wrap_io(self, client: StreamIO) -> StreamIO:
4343
return PrefixStreamIO(client)
4444

4545
async def run(self):
46+
print("StdioServer started", file=sys.stderr, flush=True)
4647
self._client = StdioClient()
4748
await self._handle_client(self._client)

tests/io/stream_io_test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import subprocess
2+
import sys
3+
14
import pytest
25
import anyio
36

@@ -203,3 +206,32 @@ async def test_exact_read_of_partial_chunks(self, stream):
203206
result = await prefix_io.read(4096)
204207
assert result == payload
205208
assert len(result) == 100
209+
210+
211+
class TestStdioServerSubprocess:
212+
213+
def test_binary_pipe_roundtrip(self):
214+
"""
215+
Spawn the StdioServer as a subprocess and pipe a framed JSON-RPC
216+
request to its stdin (as raw bytes). Confirms sys.stdin.buffer /
217+
sys.stdout.buffer is used — text-mode streams would break this.
218+
"""
219+
msg = b'{"jsonrpc":"2.0","id":1,"method":"eval","params":{}}'
220+
frame = f"Content-Length: {len(msg)}\r\n\r\n".encode() + msg
221+
222+
proc = subprocess.Popen(
223+
[sys.executable, "-c",
224+
"import anyio; from lf_toolkit.io.stdio_server import StdioServer; "
225+
"anyio.run(StdioServer().run)"],
226+
stdin=subprocess.PIPE,
227+
stdout=subprocess.PIPE,
228+
stderr=subprocess.PIPE,
229+
)
230+
231+
stdout, stderr = proc.communicate(input=frame, timeout=5)
232+
233+
# Must receive a framed response
234+
assert b"Content-Length:" in stdout, (
235+
f"No framed response received.\nstderr: {stderr.decode()}"
236+
)
237+
assert b"jsonrpc" in stdout

0 commit comments

Comments
 (0)