From 1efb0094c8fe3500c53315036aabf51979e1a258 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Tue, 25 Aug 2026 12:13:03 +0800 Subject: [PATCH] fix(code-runtime-python): bind the original std streams' flush methods, not the stream objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The settlement drain iterated the bound stream OBJECTS, which are not callable — every _flush() raised TypeError and was swallowed by the loop's except, so the drain never ran and only the -u flag carried the behavior. Bind sys.__stdout__.flush/sys.__stderr__.flush (bound methods, capturing the stream at binding time, immune to a later sys.__stdout__ rebind; None-guarded). Verified by removing -u temporarily: the sys.__stdout__ regression test still passes, so the drain is a genuine backstop, not a documented-but-dead layer. --- .../code-runtime/code-runtime-python/py/bootstrap.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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