Question

I am trying to figure out a way to redirect output from a script that I'm writing that runs the interactive console.

I need to be able to:

capture the output in a string, and then check it, or print it out.

Is this doable? Should I be using a different python module?

I tried this with the subprocess module, but ran into a problem where I could only do 1 read at the end of the process. That won't work, I need to read multiple times from stdout. This is what I have so far:

import code
console = code.InteractiveConsole()
console.push('from sim import newsteam\n')
console.push('assembler = newsteam()\n')
console.push('assembler.__init__()\n')

line = console.push('assembler.reportr()\n')
#I need to be able to interact with this output
line1 = console.push('assembler.reportpc()\n')
line2 = console.push('assembler.reportm()\n')

print("this is the result: " + line + line1 + line2)
Was it helpful?

Solution

You could redirect the stdout temporarily:

import code
import sys
from contextlib import contextmanager

try:
    from StringIO import StringIO
except ImportError: # Python 3
    from io import StringIO

try:
    from contextlib import redirect_stdout 
except ImportError: # Python < 3.4
    @contextmanager
    def redirect_stdout(new_target):
        old_target, sys.stdout = sys.stdout, new_target # replace sys.stdout
        try:
            yield new_target # run some code with the replaced stdout
        finally:
            sys.stdout = old_target # restore to the previous value

f = StringIO()
with redirect_stdout(f):
    console = code.InteractiveConsole()
    console.push('print("hello world")')
    console.push('i = int(input("give me a number"))')
    console.push('sq = i*i')
    console.push('print("%d squared is %d" % (i, sq))')
print("Got: %r" % f.getvalue())

Example:

$ echo 2 | python code-interactive.py 
Got: 'hello world\ngive me a number2 squared is 4\n'

OTHER TIPS

Perhaps you could try using subprocess Popen, spawn IDLE as a subprocess, and manually handle stdin and stdout using pipes. However, if you go that route read up on solutions for non-blocking read/writes. By default, reads (ie. readlines()) will keep reading until the subprocess ends. It appears you need it to be interactive (handling both stdin and stdout). Check out this thread.

You can use a local variable to store the results generated inside the console.

For instance:

import code
output = []
console = code.InteractiveConsole({'output':output})
console.push('import sys')
line = console.push('output.append(sys.version)')
print('Result value:', output)

You'll get a list with the output lines you want to check in your main module.

In your case you could do something like:

import code
output = []
console = code.InteractiveConsole({'output': output})
console.push('from sim import newsteam\n')
console.push('assembler = newsteam()\n')
console.push('assembler.__init__()\n')

console.push('output.append(assembler.reportr())')
console.push('output.append(assembler.reportpc())')
console.push('output.append(assembler.reportm())')

print("this is the result: ", output)
pop = subprocess.Popen([ "command",'argument'] , stdin=subprocess.PIPE , stdout =subprocess.PIPE  )  
while True:
    l = pop.stdout.readline()
    if not l :
        break 
    if l == '':
        time.sleep(1)
        continue 
    # do some function with l 
    # ....

N.B:. Not tested, but it should work.

thanks for @ J.F. Sebastian_comment

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top