Last active
December 9, 2015 23:18
-
-
Save russelldavis/4342870 to your computer and use it in GitHub Desktop.
Like check_output, but also tees the output to a file object specified by the stdout kwarg. Passing in stdout=sys.stdout allows you to run the process with normal output (like check_call()) but also get the output as the return value (like check_output()).
This file contains 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
from subprocess import Popen, PIPE, CalledProcessError | |
def check_teed_output(*popenargs, **kwargs): | |
""" | |
Like check_output, but also tees the output to a file object specified | |
by the stdout kwarg. Passing in stdout=sys.stdout allows you to run the | |
process with normal output (like check_call()) but also get the output | |
as the return value (like check_output()). | |
""" | |
stdout = kwargs.pop('stdout', None) | |
if stdout is None: | |
raise ValueError('stdout argument is required') | |
process = Popen(stdout=PIPE, *popenargs, **kwargs) | |
if [process.stdin, process.stdout, process.stderr].count(None) < 2: | |
# As currently implemented, if more than one pipe is present, the call | |
# to readline below could deadlock (see warnings in the subprocess docs) | |
# That use-case should be pretty rare, but if needed, this could be | |
# modified to use select or poll | |
raise ValueError("check_streamed() doesn't support more than one pipe") | |
lines = [] | |
for line in iter(process.stdout.readline, ''): | |
stdout.write(line) | |
stdout.flush() | |
lines.append(line) | |
output = ''.join(lines) | |
if process.wait(): | |
cmd = kwargs.get("args") | |
if cmd is None: | |
cmd = popenargs[0] | |
raise CalledProcessError(process.returncode, cmd, output=output) | |
return output |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment