@@ -127,7 +127,7 @@ async def stdio_client(server: StdioServerParameters, errlog: TextIO = sys.stder
127
127
cwd = server .cwd ,
128
128
)
129
129
130
- async def stdout_reader ():
130
+ async def stdout_reader (done_event : anyio . Event ):
131
131
assert process .stdout , "Opened process is missing stdout"
132
132
133
133
try :
@@ -151,6 +151,7 @@ async def stdout_reader():
151
151
await read_stream_writer .send (message )
152
152
except anyio .ClosedResourceError :
153
153
await anyio .lowlevel .checkpoint ()
154
+ done_event .set ()
154
155
155
156
async def stdin_writer ():
156
157
assert process .stdin , "Opened process is missing stdin"
@@ -174,21 +175,30 @@ async def stdin_writer():
174
175
anyio .create_task_group () as tg ,
175
176
process ,
176
177
):
177
- tg .start_soon (stdout_reader )
178
+ stdout_done_event = anyio .Event ()
179
+ tg .start_soon (stdout_reader , stdout_done_event )
178
180
tg .start_soon (stdin_writer )
179
- # tg.start_soon(monitor_process, tg.cancel_scope)
180
181
try :
181
182
yield read_stream , write_stream
183
+ if stdout_done_event .is_set ():
184
+ # The stdout reader exited before the calling code stopped listening
185
+ # (e.g. because of process error)
186
+ # Give the process a chance to exit if it was the reason for crashing
187
+ # so we can get exit code
188
+ with anyio .move_on_after (0.1 ) as scope :
189
+ await process .wait ()
190
+ process_error = f"Process exited with code { process .returncode } ."
191
+ if scope .cancelled_caught :
192
+ process_error = (
193
+ "Stdout reader exited (process did not exit immediately)."
194
+ )
182
195
finally :
183
196
await read_stream .aclose ()
184
197
await write_stream .aclose ()
185
198
await read_stream_writer .aclose ()
186
199
await write_stream_reader .aclose ()
187
-
188
- if process .returncode is not None and process .returncode != 0 :
189
- process_error = f"Process exited with code { process .returncode } ."
190
- else :
191
- # Clean up process to prevent any dangling orphaned processes
200
+ # Clean up process to prevent any dangling orphaned processes
201
+ if process .returncode is None :
192
202
if sys .platform == "win32" :
193
203
await terminate_windows_process (process )
194
204
else :
0 commit comments