Repository navigation
fix(incremental): treat NUL stdin on Windows as non-interactive - #1166
Merged
1 commit merged intoNov 9, 2026
Merged
1 commit merged into
1 commit merged into
Conversation
On Windows, isatty() is True for every character device, including the NUL device that subprocess.DEVNULL and Node's stdio "ignore" provide. The Windows non-TTY fallback from tirth8205#46 and tirth8205#136 therefore did not apply, and the parse step started a ProcessPoolExecutor. When the caller then ended the run, Windows left the pool workers behind as orphans. Stdin now counts as interactive on Windows only when its handle accepts GetConsoleMode, which a console accepts and NUL, files and pipes refuse. Closes tirth8205#1163 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d01c1fd
HengYangDS
pushed a commit
to HengYangDS/code-review-graph
that referenced
this pull request
Nov 9, 2026
…ld (review of tirth8205#1166) The Windows console check could raise ImportError (a Python without ctypes) or ctypes.ArgumentError (a handle too large to pass as a C int), and both went straight through _select_executor_kind into the build. The old isatty() check could not fail that way. Both now mean "not a console", which picks the thread executor. Adds tests that run the real check with stand-ins for msvcrt and kernel32 on every platform, and one for a missing sys.stdin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HengYangDS
pushed a commit
to HengYangDS/code-review-graph
that referenced
this pull request
Nov 9, 2026
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.
Linked issue
Closes #1163
What & why
On Windows,
isatty()is True for every character device, including theNULdevice. A parent gives a childNULas stdin throughsubprocess.DEVNULLor Node'sstdio: "ignore". In that case the Windows non-TTY fallback in_select_executor_kind()(#46, #136) did not apply, and parsing used aProcessPoolExecutor. When the parent then ended the run, for example a pre-commit hook with a timeout, Windows did not end the pool workers. Each run could leave up to 8 orphanedspawn_mainprocesses. On one development machine about 1,400 of them collected and held about 7.6 GB.This PR adds
_stdin_is_interactive(). On Windows it returns True only when the stdin handle acceptsGetConsoleMode. A console accepts that call, andNUL, files and pipes refuse it. On other platforms the result is the same asisatty(), so the Linux and macOS executor choice does not change.CRG_PARSE_EXECUTORstill overrides everything.How it was tested
On Windows 11, CPython 3.12 (uv):
New tests:
test_windows_nul_stdin_uses_threads: Windows,isatty()True, no console handle, so the result isthread.test_windows_console_stdin_keeps_process_default: Windows, a console handle, so the result isprocess.test_real_nul_stdin_is_not_interactive_on_windows(Windows only): a real child withstdin=DEVNULLreportsisatty()True,_stdin_is_interactive()False and executorthread.Measured effect on a repository with about 650 files: a full build with the old selection reached 8 pool workers in 58 s. With the thread executor it reached 0 workers in 60 s.
Limits:
staging.🤖 Generated with Claude Code