Skip to content

[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
wntrblm:mainfrom
felixfontein:capture
Draft

Conversation

@felixfontein

Copy link
Copy Markdown

Session.run_capture()'s interface is similar to Session.run(), except:

  • It always returns tuple[str, str, int] (unless the command isn't run, then it returns None) with return code, stdout, and stderr;
  • If silent=True is specified and the program exits abnormally, stderr is shown; if silent=False (default), all stdout and stderr is shown in near real-time (similar to tee, you catch the output while the user can still see it);
  • There is a success_all: bool parameter which, when set to True, 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 for success_codes.

The implementation of silent=False was 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 to KeyboardInterrupt. I had to add a SIGINT signal handler and cancel tasks myself. (By default SIGINT kills the event loop, and not even finally blocks in tasks are handled... You can only catch KeyboardInterrupt completely outside the loop.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 how Popen.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.

… and stderr separately, even while showing the result.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Allow session.run(quiet=True) to return stdout and stderr separately

1 participant