6 # From https://stackoverflow.com/a/29834357
7 class OutputGrabber(object):
9 Class used to grab standard output or another stream.
13 def __init__(self
, stream
=None, threaded
=False):
14 self
.origstream
= stream
15 self
.threaded
= threaded
16 if self
.origstream
is None:
17 self
.origstream
= sys
.stdout
18 self
.origstreamfd
= self
.origstream
.fileno()
19 self
.capturedtext
= ""
20 # Create a pipe so the stream can be captured:
21 self
.pipe_out
, self
.pipe_in
= os
.pipe()
27 def __exit__(self
, type, value
, traceback
):
32 Start capturing the stream data.
34 self
.capturedtext
= ""
35 # Save a copy of the stream:
36 self
.streamfd
= os
.dup(self
.origstreamfd
)
37 # Replace the original stream with our write pipe:
38 os
.dup2(self
.pipe_in
, self
.origstreamfd
)
40 # Start thread that will read the stream:
41 self
.workerThread
= threading
.Thread(target
=self
.readOutput
)
42 self
.workerThread
.start()
43 # Make sure that the thread is running and os.read() has executed:
48 Stop capturing the stream data and save the text in `capturedtext`.
50 # Print the escape character to make the readOutput method stop:
51 self
.origstream
.write(self
.escape_char
)
52 # Flush the stream to make sure all our data goes in before
53 # the escape character:
54 self
.origstream
.flush()
56 # wait until the thread finishes so we are sure that
57 # we have until the last character:
58 self
.workerThread
.join()
62 os
.close(self
.pipe_in
)
63 os
.close(self
.pipe_out
)
64 # Restore the original stream:
65 os
.dup2(self
.streamfd
, self
.origstreamfd
)
66 # Close the duplicate stream:
67 os
.close(self
.streamfd
)
71 Read the stream data (one byte at a time)
72 and save the text in `capturedtext`.
75 char
= os
.read(self
.pipe_out
,1).decode(self
.origstream
.encoding
)
76 if not char
or self
.escape_char
in char
:
78 self
.capturedtext
+= char