Reopen sys.__std*__ on Windows consoles so they follow fd capture#14736
Open
Abhishek-kroy wants to merge 1 commit into
Open
Reopen sys.__std*__ on Windows consoles so they follow fd capture#14736Abhishek-kroy wants to merge 1 commit into
Abhishek-kroy wants to merge 1 commit into
Conversation
On Windows, when attached to a console, the sys.__std{in,out,err}__
streams are backed by _WindowsConsoleIO, which writes through the
console handle rather than the file descriptor and whose isatty()
unconditionally returns True. As a result, while FDCapture had
redirected the fds, sys.__stdout__.isatty() kept returning True (unlike
on POSIX, where it returns False), and writes to sys.__stdout__ either
escaped capturing and appeared on the terminal or failed with
"OSError: [WinError 6] The handle is invalid" once dup2 had closed the
console handle.
Extend _windowsconsoleio_workaround to also reopen the dunder streams,
backed by their original file descriptors. The raw stream is built
explicitly with io.FileIO because open() on a console fd would produce
another _WindowsConsoleIO.
Closes pytest-dev#12349
Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #12349
The problem
On Windows, when attached to a console,
sys.__stdin__/sys.__stdout__/sys.__stderr__are backed by_io._WindowsConsoleIO, which writes through the console handle rather than the file descriptor, and whoseisatty()unconditionally returnsTrue.So while
FDCapturehasdup2-ed the fds away (--capture=fd, the default):sys.__stdout__.isatty()keeps returningTrue, whileos.isatty(1)correctly returnsFalse— unlike POSIX, where both returnFalse(this is the exact assertion failure reported in sys.__stdout__.isatty() returns incorrect value for Windows 11 #12349, reproduced on Windows 11);sys.__stdout__either escape capturing and are printed straight to the terminal, or fail withOSError: [WinError 6] The handle is invalidoncedup2has closed the console handle (the very handle instability already described in_windowsconsoleio_workaround's docstring).The fix
Extend
_windowsconsoleio_workaroundto also reopen the dunder streams, backed by their original file descriptors (unlikesys.std*, which keep being reopened on duplicated fds for handle isolation). The raw stream is constructed explicitly withio.FileIO, becauseopen()on a console fd produces another_WindowsConsoleIOand would change nothing.After the fix the dunder streams follow fd redirection exactly like on POSIX:
isatty()reflects the actual state of the fd, writes during capture land in the capture file, and writes outside capture reach the console.sys.__stdin__.encodingandsys.__stderr__.fileno()(used by the faulthandler plugin) are preserved.Verification on Windows 11
Running the reproducer from #12349 under a real console (ConPTY), before the fix:
and a write probe showed
OSError(9, 'The handle is invalid')plus output leaking to the terminal despite capture being active.After the fix, both asserts from the issue pass, and writes to
sys.__stdout__are captured.testing/test_capture.py(131 tests),testing/test_terminal.pyandtesting/test_faulthandler.pyall pass both piped and under a real console on Windows 11.The new regression test fakes the console environment (monkeypatched
sys.platformandio._WindowsConsoleIO), so it exercises this code path on all platforms/CI runners, where no real console is available.closes #XYZWto the PR description and/or commits (whereXYZWis the issue number).Co-authored-bycommit trailers.changelogdirectory (changelog/12349.bugfix.rst).AUTHORSin alphabetical order.Disclosure per the AI/LLM-Assisted Contributions Policy: this change was developed with AI assistance (Claude Code), credited in the commit trailer. I take responsibility for the change and will respond to review feedback myself.