[WIP] Add a new method Session.run_capture() which allows to capture stdout and stderr separately, even while showing the result#1124
Draft
felixfontein wants to merge 1 commit into
Draft
Conversation
… and stderr separately, even while showing the result.
This was referenced Jul 4, 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.
Session.run_capture()'s interface is similar toSession.run(), except:tuple[str, str, int](unless the command isn't run, then it returnsNone) with return code, stdout, and stderr;silent=Trueis specified and the program exits abnormally, stderr is shown; ifsilent=False(default), all stdout and stderr is shown in near real-time (similar totee, you catch the output while the user can still see it);success_all: boolparameter which, when set toTrue, does not fail on any return code; that allows the caller to completely handle the return code, without having to provide an exhaustive list of possible return codes forsuccess_codes.The implementation of
silent=Falsewas somewhat tricky. I found https://stackoverflow.com/questions/5045771/python-how-to-prevent-subprocesses-from-receiving-ctrl-c-control-c-sigint and the resulting https://github.com/pycontribs/subprocess-tee/blob/main/src/subprocess_tee/__init__.py implementation, but that didn't work as I expected in particular with respect toKeyboardInterrupt. I had to add a SIGINT signal handler and cancel tasks myself. (By default SIGINT kills the event loop, and not evenfinallyblocks in tasks are handled... You can only catchKeyboardInterruptcompletely outside theloop.run_until_complete()call.)I also considered not using asyncio, but selecting on stdout/stderr, i.e. basically reimplementing
Popen.communicate(). But then I looked closer in howPopen.communicate()is implemented in the standard library, and decided it's way too complex to try to do it this way, especially when it also has to work on Windows.This is a work in progress since it doesn't have tests yet. Also I only did a few tests on Linux (I don't have access to Windows, but can do some manual testing on macOS later). Before I spent even more time I'm also curious on whether this has a chance of being merged :)
Fixes #1053.