Reputation: 1708
This is what I am trying to achieve
def fun():
runner = InteractiveConsole()
while(True):
code = raw_input()
code.rstrip('\n')
# I want to achieve the following
# By default the output and error of the 'code' is sent to STDOUT and STDERR
# I want to obtain the output in two variables out and err
out,err = runner.push(code)
All the solution that I have looked at till now, use either pipes to issue separate script execution command (which is not possible in my case). Any other way I can achieve this?
Upvotes: 3
Views: 6739
Reputation: 97555
import StringIO, sys
from contextlib import contextmanager
@contextmanager
def redirected(out=sys.stdout, err=sys.stderr):
saved = sys.stdout, sys.stderr
sys.stdout, sys.stderr = out, err
try:
yield
finally:
sys.stdout, sys.stderr = saved
def fun():
runner = InteractiveConsole()
while True:
out = StringIO.StringIO()
err = StringIO.StringIO()
with redirected(out=out, err=err):
out.flush()
err.flush()
code = raw_input()
code.rstrip('\n')
# I want to achieve the following
# By default the output and error of the 'code' is sent to STDOUT and STDERR
# I want to obtain the output in two variables out and err
runner.push(code)
output = out.getvalue()
print output
In newer versions of python, this contezt manager is built in:
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
...
Upvotes: 8
Reputation: 4150
InteractiveConsole doesn't expose any API for setting a file like object for output or errors, you'll need to monkey patch sys.stdout
and sys.stderr
. As always with monkey patching, be mindful of what the side effects might be. In this case, you'd be replacing the global stdin and stdout file objects with your own implementation, which might swallow up unintended output as well (especially if you're using any threads).
It would be slightly safer to 'tee' the output with something like:
import sys
import StringIO
class TeeBuffer(object):
def __init__(self, real):
self.real = real
self.buf = StringIO.StringIO()
def write(self, val):
self.real.write(val)
self.buf.write(val)
def fun():
runner = InteractiveConsole()
out = TeeBuffer(sys.stdout)
err = TeeBuffer(sys.stderr)
sys.stdout = out
sys.stderr = err
while(True):
code = raw_input()
code.rstrip('\n')
out, err = runner.push(code)
outstr = out.buf.getvalue()
errstr = err.buf.getvalue()
sys.stdout = out.real
sys.stderr = err.real
Then your user still sees the output, without you having to worry about printing it back out to the correct place on each run.
Upvotes: 1
Reputation: 123612
You can use a context manager to redirect stdout temporarily:
@contextmanager def stdout_redirected(new_stdout): save_stdout = sys.stdout sys.stdout = new_stdout try: yield None finally: sys.stdout = save_stdout
Used as follows:
with opened(filename, "w") as f: with stdout_redirected(f): print "Hello world"
This isn't thread-safe, of course, but neither is doing this same dance manually. In single-threaded programs (for example, in scripts) it is a popular way of doing things.
It's easy to tweak this to redirect both stdout
and stderr
to cStringIO
s:
@contextmanager
def out_redirected():
save_stdout = sys.stdout
save_stderr = sys.stderr
sys.stdout = cStringIO.String()
sys.stderr = cStringIO.String()
try:
yield sys.stdout, sys.stderr
finally:
sys.stdout = save_stdout
sys.stderr = save_stderr
You'd use this as
with out_redirected() as out, err:
runner.push(code)
out.seek(0)
print out.read()
Upvotes: 0