0

In the following case, I am trying to print all output of temp2 script (which is run through subprocess) on to a textbox widget in realtime basis.

The problem I am facing is this, in temp2, for i <= 468, the script is working fine and to me it appears to be real time.

However, if i put i = 469 or above, the execution halts after many iterations without finishing.

So for example, for i = 469, the log file has entries for i = 469 to i = 3. There after the whole process halts.

Please note: the value i = 469 may not be the same for your machine. If i = 469 works fine for you, try some higher value.

Temp1.py is the main script.

#temp1.py
from Tkinter import *
import Tkinter as tk
import os
import ttk 
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
import sys

#Creating new Window to display output 
t = Tk()
t.title('output Run Display')
t.geometry('800x1000-5+40')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=115, height=150, wrap='none')
log.grid(row = 1, column = 0)

test=subprocess.Popen('temp2',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)


#stdout
while True:
    line_out = test.stdout.readline()
    line_er  = test.stderr.readline()
    if line_out == "" and line_er == "":
        break
    else:
        log['state'] = 'normal'
        log.insert('end', line_out)
        log.insert('end', line_er)
        log['state'] = 'disabled'
        print line_out
        print line_er
        t.update()
t.mainloop()

And below is the script i am running through the subprocess.

#temp2 #csh script

set i = 469
while ($i > 0)
  echo i is $i | tee -a log
  set i = `expr "$i" - 1`
end 
Ani
  • 918
  • 1
  • 10
  • 25
  • 1
    Is the `else:` line correctly indented? Also the lines below seem invalid... – eumiro Nov 28 '11 at 10:30
  • It was ok in my interpreter, corrected here some indentation errors due to copy-paste from unix to window machine – Ani Nov 28 '11 at 11:19

3 Answers3

1

Your problem is that the call to test.stdout.readline is blocking - which means processing will stop there and only resume when there is a new line of data avalilable which is returned.

The same is true for test.stderr.readline of course.

I think the simplest way of dealing with what you want is having your subprocess write to a file on the filesystem, you open that file on your main process, and try to read from it inside a tkinter callback function called regularly with the .after tkinter method.

(witha file on filesystem you can use seek and tell methods to check if you are at the end of file)

Note that in the code you placed as example, your call to Tkinter.mainloop is only reached after the subprocess is exausted already.

A better yet solution would be to read the logs you want entirely in Python without relying to a shell script.

Tkinter.after is similar to javascript's settimeout - it is a method on a widget (say, your "t" object), and you pass it the number of miliseconds to wait, and the name of the function to be called -

like in

def verify_output():
    # read subprocess output file and update the window if needed
    ...
    # call self after 1 second
    t.after(1000, verify_output)

# callreader callback for the first time:

t.after(10, verify_output)
Tkinter.mainloop()
jsbueno
  • 99,910
  • 10
  • 151
  • 209
0
import os
import ConfigParser
from Tkinter import *
import Tkinter as tk
import os
import ttk 
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
from subprocess import call
import sys

os.system('rm stdout')

#Creating new Window to display output 
t = Tk()
t.title('output Run Display')
t.geometry('100x100')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=50, height=50, wrap='none')
log.grid(row = 1, column = 0,sticky=(N,W,E,S))
s = ttk.Scrollbar(t,orient=VERTICAL,command=log.yview)
s.grid(column=1,row=1,sticky=(N,S))
log.configure(yscrollcommand=s.set)
ttk.Sizegrip().grid(column=1, row=1, sticky=(S,E))

with open("stdout","wb") as out:
    with open("stderr","wb") as err:
        test=subprocess.Popen('tem',shell=True,stdout=out,stderr=err)
fout = open('stdout','r')
ferr = open('stderr','r') 
def verify():

    data_out = fout.readlines()
    data_out = ''.join(data_out)

    log['state'] = 'normal'
    log.insert('end',data_out)
    log['state'] = 'disabled'
    #print data_out

    t.after(1000,verify)
    fout.close()

verify()

t.mainloop()
Ani
  • 918
  • 1
  • 10
  • 25
0

As jsbueno answer, you problem come from blocking call to readline. You may instead use a file event source to get notified when data are available (through createfilehandler tkinter method). See this previous answer for details.

Community
  • 1
  • 1
FabienAndre
  • 4,514
  • 25
  • 38