diff --git a/packages/code-runtime/code-runtime-python/py/bootstrap.py b/packages/code-runtime/code-runtime-python/py/bootstrap.py index b87af78de6..ed6c5b1c6a 100644 --- a/packages/code-runtime/code-runtime-python/py/bootstrap.py +++ b/packages/code-runtime/code-runtime-python/py/bootstrap.py @@ -958,8 +958,14 @@ async def _run(channel: ProtocolChannel) -> None: # Binding the names here (before the program) makes them immune to a # `sys.__stdout__ = boom` rebind in model code; `None` under `-S`-style # redirects is guarded at flush time. - _stdout_orig = sys.__stdout__ - _stderr_orig = sys.__stderr__ + # Bind the FLUSH METHODS, not the stream objects: the settlement flush + # loop iterates callables, and a bare TextIOWrapper object is not callable — + # invoking it would raise TypeError and be swallowed by the loop's except, + # silently disabling the drain. A bound method captures its stream at + # binding time, so a later `sys.__stdout__ = boom` rebind cannot redirect + # it; `None` (stream absent) is guarded at flush time. + _stdout_orig = sys.__stdout__.flush if sys.__stdout__ is not None else None + _stderr_orig = sys.__stderr__.flush if sys.__stderr__ is not None else None # 6. Compile the program as the body of an async function, matching the # seam contract (`CodeRunRequest.program` is an async-function body: top-level