Run an external Python script from wxPython GUI

Dear all,
I have been trying to figure out how I can execute a Python script from a GUI but with no luck. Searching the internet I have come across several ideas (threading, subprocess, etc…) but I do not seem to get it right. To illustrate what I need to do, below is a simple GUI that I have built.

############################################################
import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 300))
        self.SetTitle("TEST")

        self.panel_1 = wx.Panel(self, wx.ID_ANY)

        sizer_1 = wx.BoxSizer(wx.VERTICAL)

        grid_sizer_1 = wx.FlexGridSizer(5, 2, 1, 1)
        sizer_1.Add(grid_sizer_1, 1, wx.EXPAND, 0)

        label_1 = wx.StaticText(self.panel_1, wx.ID_ANY, "x")
        grid_sizer_1.Add(label_1, 0, wx.ALL, 5)

        self.text_ctrl_1 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
        grid_sizer_1.Add(self.text_ctrl_1, 0, 0, 0)

        label_2 = wx.StaticText(self.panel_1, wx.ID_ANY, "y")
        grid_sizer_1.Add(label_2, 0, wx.ALL, 5)

        self.text_ctrl_2 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
        grid_sizer_1.Add(self.text_ctrl_2, 0, 0, 0)

        grid_sizer_1.Add((0, 0), 0, 0, 0)

        self.button_1 = wx.Button(self.panel_1, wx.ID_ANY, "Save")
        self.button_1.SetFocus()
        grid_sizer_1.Add(self.button_1, 0, 0, 0)

        grid_sizer_1.Add((0, 0), 0, 0, 0)

        self.button_2 = wx.Button(self.panel_1, wx.ID_ANY, "Start")
        grid_sizer_1.Add(self.button_2, 0, 0, 0)

        grid_sizer_1.Add((0, 0), 0, 0, 0)

        self.button_3 = wx.Button(self.panel_1, wx.ID_ANY, "Stop")
        grid_sizer_1.Add(self.button_3, 0, 0, 0)

        self.panel_1.SetSizer(sizer_1)

        self.Layout()

        self.Bind(wx.EVT_BUTTON, self.OnClick_Save, self.button_1)
        self.Bind(wx.EVT_BUTTON, self.OnClick_Start, self.button_2)
        self.Bind(wx.EVT_BUTTON, self.OnClick_Stop, self.button_3)

    def OnClick_Save(self, event):  
        data = []
        x = float(self.text_ctrl_1.GetValue())
        data.append(x)
        y = float(self.text_ctrl_2.GetValue())
        data.append(y)

        event.Skip()

    def OnClick_Start(self, event):  
        # Button "Start" runs the module (script)
        event.Skip()

    def OnClick_Stop(self, event):  
        # Button "Stop" aborts the run
        event.Skip()

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

if __name__ == "__main__":
    Test = MyApp(0)
    Test.MainLoop()
################################################################

For a start, the external Python script I am trying to run from the above GUI is a sympy code:

################################################################
import sympy
from sympy import symbols, sin, cos, N

x, y = symbols('x, y')

z = N(sin(x) + cos(y))

print(z)
################################################################

What I am hoping to achieve is:

  1. Running the external script after entering the values of x and y in the text controls and clicking the ‘Save’ followed by the ‘Start’ buttons.
  2. Being able to abort the run by clicking the ‘Stop’ button.
  3. Writing the output (results of the calculation) to a text file (preferred method ) or to the GUI.

Please note that the real life scripts that I will be running will take from several minutes to possibly several hours to complete.

If it is of help, here are the details of what I am using: Python 3.8.5; wxPython 4.1.0 and MSW 10 64 bit.

Any help is highly appreciated.
Many thanks in advance.

omar

Well, apart from how to effect stopping you never do start
the external script as far as I can see ?

Karsten

This was discussed here a few months ago, see Jul 23 :slight_smile: Newbie: how do I start a Python process that runs in parallel to the GUI event loop?

@electrogas Thanks for the link. I will go through the discussion and try to build on from there.

Dear all,
Following the recommended links, I am attaching here a working script for the GUI. I kindly request your help regarding the following issues:

  1. I am not sure whether or not the window closing method I implemented is the right one. In this link, it is mentioned that setting the thread as daemon is sufficient. However, in this answer, even though the thread is created as daemon, a close window method is also implemented.
  2. In case of having an error after starting the run (for example if I set “y” value to zero which will throw an error “division by zero”), the app will show “running …” forever and trying to stop it will show “trying to abort …” forever. Is there a way of resetting rather than closing the main window (X)? I tried to use a button bound to a method similar to that I used for window closing but it did not have any effect.

Any help and comments are highly appreciated.
Many thanks in advance,

omar

gui_v2_5.py (7.8 KB) module_sine.py (191 Bytes)