Skip to content

Instantly share code, notes, and snippets.

@russelldavis
Last active December 9, 2015 23:18
Show Gist options
  • Save russelldavis/4342870 to your computer and use it in GitHub Desktop.
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()).
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