wxpython gui blocking on wx.TextCtrl

I am running this application which SSH’s into a Windows Server, then whilst running gets the stdout into self.output_file via io.BytesIO(), which all works fine. But when I try to display this in the TextCtrl the gui freezes and nothing is displayed, I am using wx.CallAfter(self.parent.running_log.AppendText, self.output_file.getvalue()) which is running in a separate thread. If I change that to just a print self.output_file.getvalue()everything works fine. But I need this to display in the TextCtrl window. What am I doing wrong?

Here is my current code:

import wx
from subprocess import Popen, PIPE, STDOUT
import sys
import spur
import threading
import os
import time
import io
class MainWindow(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(600, 500), style=wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER |
                                                wx.RESIZE_BOX |
                                                wx.MAXIMIZE_BOX))

        self.running_log = wx.TextCtrl(self, pos=(5, 5), size=(570,390))
        self.buttonGo = wx.Button(self, -1, "Go", pos=(180,420))
        self.buttonGo.Bind(wx.EVT_BUTTON, self.Go)
        self.buttonClose = wx.Button(self, -1, "Quit", pos=(285,420))
        self.buttonClose.Bind(wx.EVT_BUTTON, self.OnClose)
        self.sshLog1 = sshLog(self)
        self.Centre()
        self.Show()

    def Go(self, event):
        threading.Thread(target=self.sshLog1.runCommand).start()
        threading.Thread(target=self.sshLog1.readFile).start()

    def OnClose(self, e):
        CloseApp()

class sshLog(wx.Panel):
    def __init__(self, parent):
        self.parent = parent
self.frame = self
def runCommand(self):
        self.output_file = io.BytesIO()
        shell = spur.SshShell(hostname='10.1.1.100', username='remoteUsername', password='remotePassword', missing_host_key=spur.ssh.MissingHostKey.accept)
        result = shell.spawn(['ping', 'google.com', '-t'], stdout=self.output_file)
        result.wait_for_result()

    def readFile(self):
        time.sleep(1)
        while True:
            wx.CallAfter(self.parent.running_log.AppendText, self.output_file.getvalue())
            #print self.output_file.getvalue()

    def OnClose(self, e):
        CloseApp()

<details class='elided'>
<summary title='Show trimmed content'>&#183;&#183;&#183;</summary>

###############################
########## CLOSE APP ##########
###############################
class CloseApp(wx.Frame):
    def __init__(e):
        sys.exit(0)

app = wx.App()
MainWindow(None, -1, 'My App')
app.MainLoop()

This:
That is a tight infinite loop. You are flooding your message queue
with an infinite number of CallAfter requests. Remember that
CallAfter doesn’t wait for the call to complete. It just returns,
loops around, and queues another one.
What did you intend here? Are you expecting “output_file” to grow
over time? If so, then you probably don’t want to append its entire
contents every time. You’d just want to add whatever is new, and
not queue anything at all if there is no new text.

···

kevjwells wrote:

      I am running this application which SSH's into a

Windows Server, then whilst running gets the stdout into self.output_file via io.BytesIO() , which all
works fine. But when I try to display this in the TextCtrl the
gui freezes and nothing is displayed, I am using wx.CallAfter(self.parent.running_log.AppendText, self.output_file.getvalue()) which is running in a separate
thread. If I change that to just a print self.output_file.getvalue() everything
works fine. But I need this to display in the TextCtrl window.
What am I doing wrong?

    def readFile(self):
        time.sleep(1)
        while True:
            wx.CallAfter(self.parent.running_log.AppendText, self.output_file.getvalue())
-- Tim Roberts, Providenza & Boekelheide, Inc.

timr@probo.com