Gregg Lind
Gregg Lind

Reputation: 21218

Sensible Way to Capture Stdout for Later Replay?

As part of trying to test a legacy function's 'print to stdout' side-effect, I want to capture stdout for later replay. I use mock.

goals (fulfill as many as possible!)

My implementation (below) has patching that seems a bit heavy / gross. Is there a saner way to do it? cStringIO? Any better parts of mock I can use, rather that my __getattr__ hack?

class StreamCapturing(object):
    def __init__(self, stream):
        self.captured = []
        self.stream = stream

    def __getattr__(self,attr):
        return getattr(self.stream,attr)

    def write(self, data):
        self.captured.append(data)
        self.stream.write(data)


import sys
import mock
with mock.patch('sys.stdout',StreamCapturing(sys.stdout)) as ctx:
    sys.stdout.write('a\n')
    print 'stdout'
    sys.__stdout__.write("the real one\n")
    print sys.stdout.captured
    sys.stdout.flush()

assert getattr(sys.stdout,'captured') is None

Upvotes: 1

Views: 1350

Answers (2)

fabmilo
fabmilo

Reputation: 48330

You don't even need to save the previous stdout python does it for you and yes use cStringIO

import sys
from cStringIO import StringIO

sys.stdout = captured = StringIO()
print "test string"
# test stuff
captured = captured.getvalue()
sys.stdout = sys.__stdout__
print "captured",captured

Upvotes: 2

rocksportrocker
rocksportrocker

Reputation: 7419

You do not need mock in this situation:

saved_stdout = sys.stdout
sys.stdout = StreamCapturing(saved_stdout)

print "stdout"

captured = "".join(sys.stdout.captured)
sys.stdout=saved_stdout
print "captured: ", captured

Upvotes: 0

Related Questions