python - Issues intercepting subprocess output in real time -


i've spent 6 hours on stack overflow, rewriting python code , trying work. doesn't tho. no matter do.

the goal: getting output of subprocess appear in real time in tkinter text box.

the issue: can't figure out how make popen work in real time. seems hang until process complete. (run on own, process works expected, it's thing has error)

relevant code:

import os import tkinter import tkinter.ttk tk import subprocess  class application (tk.frame):     process = 0     def __init__ (self, master=none):         tk.frame.__init__(self, master)         self.grid()         self.createwidgets()      def createwidgets (self):         self.quitbutton = tk.button(self, text='quit', command=self.quit)         self.quitbutton.grid()         self.console = tkinter.text(self)         self.console.config(state=tkinter.disabled)         self.console.grid()      def startprocess (self):         dir = "c:/folder/"         self.process = subprocess.popen([ "python", "-u", dir + "start.py" ], stdout=subprocess.pipe, stdin=subprocess.pipe, stderr=subprocess.pipe, cwd=dir)         self.updatelines()      def updatelines (self):         self.console.config(state=tkinter.normal)         while true:             line = self.process.stdout.readline().decode().rstrip()             if line == '' , self.process.poll() != none:                 break             else:                  self.console.insert(tkinter.end, line + "\n")         self.console.config(state=tkinter.disabled)         self.after(1, self.updatelines)  app = application() app.startprocess() app.mainloop() 

also, feel free destroy code if it's written poorly. first python project, don't expect @ language yet.

the problem here process.stdout.readline() block until full line available. means condition line == '' never met until process exits. have 2 options around this.

first can set stdout non-blocking , manage buffer yourself. this. edit: terry jan reedy pointed out unix solution. second alternative should preferred.

import fcntl ...      def startprocess(self):         self.process = subprocess.popen(['./subtest.sh'],             stdout=subprocess.pipe,             stdin=subprocess.pipe,             stderr=subprocess.pipe,             bufsize=0) # prevent unnecessary buffering          # set stdout non-blocking         fd = self.process.stdout.fileno()         fl = fcntl.fcntl(fd, fcntl.f_getfl)         fcntl.fcntl(fd, fcntl.f_setfl, fl | os.o_nonblock)          # schedule updatelines         self.after(100, self.updatelines)      def updatelines(self):         # read stdout as can         line = ''         while true:             buff = self.process.stdout.read(1024)             if buff:                 buff += line.decode()             else:                 break          self.console.config(state=tkinter.normal)         self.console.insert(tkinter.end, line)         self.console.config(state=tkinter.disabled)          # schedule callback         if self.process.poll() none:             self.after(100, self.updatelines) 

the second alternative have separate thread read lines queue. have updatelines pop queue. this

from threading import thread queue import queue, empty  def readlines(process, queue):     while process.poll() none:         queue.put(process.stdout.readline()) ...      def startprocess(self):         self.process = subprocess.popen(['./subtest.sh'],             stdout=subprocess.pipe,             stdin=subprocess.pipe,             stderr=subprocess.pipe)          self.queue = queue()         self.thread = thread(target=readlines, args=(self.process, self.queue))         self.thread.start()          self.after(100, self.updatelines)      def updatelines(self):         try:             line = self.queue.get(false) # false non-blocking, raises empty if empty             self.console.config(state=tkinter.normal)             self.console.insert(tkinter.end, line)             self.console.config(state=tkinter.disabled)         except empty:             pass          if self.process.poll() none:             self.after(100, self.updatelines) 

the threading route safer. i'm not positive setting stdout non-blocking work on platforms.


Comments

Popular posts from this blog

python - mat is not a numerical tuple : openCV error -

c# - MSAA finds controls UI Automation doesn't -

wordpress - .htaccess: RewriteRule: bad flag delimiters -