wx.Process and OnTerminate or wx.EVT_END_PROCESS

Hi,

Environment is:
Linux 3.11.10-17-desktop
Python 2.7.6
wx-2.9.4-gtk2

In a wx.Python app (see below) I want to launch a shell script
(minimized version see below) to execute a few things in async mode.

Problem 1:
When the shell scripts finishes I need to know the exit code.
When I use /bin/sh or /bin/bash, the exit code is sometimes correct,
in this case 7, but mostly it is -1.
When I use /bin/ksh it is up to now always correct.

Problem 2:
I do not know how to use Execute.OnTerminate() which is called when
the process finishes. My hope is, that the given status (exit code)
would be more reliable than from the wx.EVT_END_PROCESS event.

shell script: test_script ---------------------------------------------
#!/bin/bash
echo $( date ) $$
exit 7

···

-----------------------------------------------------------------------

wx.Python program: ----------------------------------------------------
#!/usr/bin/env python

# This sample demonstrates a simple use of wx.Process/wx.Execute to
# monitor an external program stdout

import wx

class ProcessFrame( wx.Frame ):

     def __init__( self, parent ):
         wx.Frame.__init__( self, parent, title='Process/Execute example' )

         panel = wx.Panel( self )
         self.label = wx.TextCtrl( panel, style=wx.TE_MULTILINE )
         self.btn = wx.Button( panel, label="Start" )

         self.process = None

         sizer = wx.BoxSizer( wx.VERTICAL )
         sizer.Add( self.label, proportion=1, flag=wx.EXPAND )
         sizer.Add( self.btn, proportion=0, flag=wx.EXPAND )
         panel.SetSizerAndFit( sizer )

         self.Bind( wx.EVT_BUTTON, self.OnButton )
         self.Bind( wx.EVT_IDLE, self.OnIdle )
         self.Bind( wx.EVT_END_PROCESS, self.OnProcessEnded )

     def OnButton( self, evnt ):
         self.btn.Enable( False )
         self.label.SetValue( '' )
         self.LongRunning()

     def LongRunning( self ):
         """
         This runs in the GUI thread but uses wx.Process and
         wx.Execute to start and monitor a separate process.
         """

         cmd = './test_script'

         self.process = wx.Process( self )
         self.process.Redirect()

         wx.Execute( cmd, wx.EXEC_ASYNC, self.process )

     def OnIdle( self, evnt ):
         """ This event handler catches the process stdout. """
         if self.process is not None:
             stream = self.process.GetInputStream()
             if stream.CanRead():
                 text = stream.read()
                 self.label.AppendText( text )

     def OnProcessEnded( self, evnt ):
         stream = self.process.GetInputStream()
         if stream.CanRead():
             text = stream.read()
             self.label.AppendText( text )

         proc_exit = evnt.GetExitCode()
         proc_ppid = evnt.GetPid()
         proc_evid = evnt.GetId()
         mssg_strg = "OnProcessEnded : proc_ppid=%s, proc_exit=%s, proc_evid=%s\n" % ( repr( proc_ppid ), repr( proc_exit ), repr( proc_evid ), )
         self.label.AppendText( mssg_strg )

         proc_ppid = self.process.GetPid()
         mssg_strg = "OnProcessEnded : proc_ppid=%s\n" % ( repr( proc_ppid ), )
         self.label.AppendText( mssg_strg )

         self.label.AppendText( 'Finished' )
         self.btn.Enable( True )

if __name__ == "__main__":
     app = wx.App(0)
     frame = ProcessFrame( None )
     frame.Show()
     app.MainLoop()
-----------------------------------------------------------------------

Any help would be appreciated.

Grüessli
--
Kurt Mueller, kurt.alfred.mueller@gmail.com

Just use
newProcess = subprocess.Popen(processPath, argList, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

then get the output (as a blocking call) with

std_out, std_err = newProcess.communicate()

Do that in a thread so the GUI doesn’t freeze. Or you could use this method, if your process doesn’t take too long to notice the GUI freezing:

···

On Friday, August 29, 2014 9:18:08 AM UTC-7, Kurt Müller wrote:

Hi,

Environment is:

Linux 3.11.10-17-desktop

Python 2.7.6

wx-2.9.4-gtk2

In a wx.Python app (see below) I want to launch a shell script

(minimized version see below) to execute a few things in async mode.

Problem 1:

When the shell scripts finishes I need to know the exit code.

When I use /bin/sh or /bin/bash, the exit code is sometimes correct,

in this case 7, but mostly it is -1.

When I use /bin/ksh it is up to now always correct.

Problem 2:

I do not know how to use Execute.OnTerminate() which is called when

the process finishes. My hope is, that the given status (exit code)

would be more reliable than from the wx.EVT_END_PROCESS event.

shell script: test_script ---------------------------------------------

#!/bin/bash

echo $( date ) $$

exit 7


wx.Python program: ----------------------------------------------------

#!/usr/bin/env python

This sample demonstrates a simple use of wx.Process/wx.Execute to

monitor an external program stdout

import wx

class ProcessFrame( wx.Frame ):

 def __init__( self, parent ):

     wx.Frame.__init__( self, parent, title='Process/Execute example' )



     panel = wx.Panel( self )

     self.label = wx.TextCtrl( panel, style=wx.TE_MULTILINE )

     self.btn = wx.Button( panel, label="Start" )



     self.process = None



     sizer = wx.BoxSizer( wx.VERTICAL )

     sizer.Add( self.label, proportion=1, flag=wx.EXPAND )

     sizer.Add( self.btn, proportion=0, flag=wx.EXPAND )

     panel.SetSizerAndFit( sizer )



     self.Bind( wx.EVT_BUTTON, self.OnButton )

     self.Bind( wx.EVT_IDLE, self.OnIdle )

     self.Bind( wx.EVT_END_PROCESS, self.OnProcessEnded )



 def OnButton( self, evnt ):

     self.btn.Enable( False )

     self.label.SetValue( '' )

     self.LongRunning()



 def LongRunning( self ):

     """

     This runs in the GUI thread but uses wx.Process and

     wx.Execute to start and monitor a separate process.

     """



     cmd = './test_script'



     self.process = wx.Process( self )

     self.process.Redirect()



     wx.Execute( cmd, wx.EXEC_ASYNC, self.process )



 def OnIdle( self, evnt ):

     """ This event handler catches the process stdout. """

     if self.process is not None:

         stream = self.process.GetInputStream()

         if stream.CanRead():

             text = stream.read()

             self.label.AppendText( text )



 def OnProcessEnded( self, evnt ):

     stream = self.process.GetInputStream()

     if stream.CanRead():

         text = stream.read()

         self.label.AppendText( text )



     proc_exit = evnt.GetExitCode()

     proc_ppid = evnt.GetPid()

     proc_evid = evnt.GetId()

     mssg_strg = "OnProcessEnded : proc_ppid=%s, proc_exit=%s, proc_evid=%s\n" % ( repr( proc_ppid ), repr( proc_exit ), repr( proc_evid ), )

     self.label.AppendText( mssg_strg )



     proc_ppid = self.process.GetPid()

     mssg_strg = "OnProcessEnded : proc_ppid=%s\n" % ( repr( proc_ppid ), )

     self.label.AppendText( mssg_strg )



     self.label.AppendText( 'Finished' )

     self.btn.Enable( True )

if name == “main”:

 app = wx.App(0)

 frame = ProcessFrame( None )

 frame.Show()

 app.MainLoop()

Any help would be appreciated.

Grüessli


Kurt Mueller, kurt.alfr...@gmail.com