Import Panel in a new thread

Overview:

I am using wxPython to make an “App store”. Basically, I am putting a
panel in a frame, adding a horizontal sizer to the panel, adding a column of buttons on the left, and then adding app panels on the right. The app panels are being imported dynamically from a shared directory. When the user clicks on a button I .hide() the current visible app then .show() the one the user clicked on.

Problem:

Everything works great until a long running process gets initiated by one of the app panels. I would like to spawn each panel in a new thread during import. Would this be possible? I don’t mind if the app panels get hung in a long running process. I would like for the buttons on the left and all the other apps to not freeze though. Unless they spawn a long running process.

This is the code I use to import the panels dynamically:

        for i, file in enumerate(os.listdir(path)):

            if file.endswith(".py"):      

                try:          

                    app_name = file[:file.rfind('.')]                                            

                    self.tool = imp.load_source('myPanel_%s'%i, path + "\\" + file)

                    self.stp1 = self.tool.myPanel(self.panel)

                    self.hbox.Add(self.stp1, 7, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=9)                

                    self.apps[app_name] = self.stp1

                    self.show_flags[app_name] = False

                    self.stp1.Hide()

                except:

                    print "You do not have access to the %s App."%app_name

Anyone see a easy way to start this line of code in a new thread?
imp.load_source(‘myPanel_%s’%i, path + “\” + file)

I am using wxPython to make an "App store". Basically, I am putting a panel
in a frame, adding a horizontal sizer to the panel, adding a column of
buttons on the left, and then adding app panels on the right. The app panels
are being imported dynamically from a shared directory. When the user clicks
on a button I .hide() the current visible app then .show() the one the user
clicked on.

Problem:
Everything works great until a long running process gets initiated by one of
the app panels. I would like to spawn each panel in a new thread during
import. Would this be possible?

in a word, no. wx is not thread safe, all GUI operation must be done
from the same thread, so you can't have different panels spawned
by/running in different threads -- that would be weird anyway, would
you want a separate event loop for each panel?

Anyway, you probably don't need the panels themselves to be in
separate thread, but rather the long running process that they create.
See the Wiki:

http://wiki.wxpython.org/LongRunningTasks

This is the code I use to import the panels dynamically:

            for i, file in enumerate(os.listdir(path)):
                if file.endswith(".py"):
                    try:
                        app_name = file[:file.rfind('.')]
                        self.tool = imp.load_source('myPanel_%s'%i, path +
"\\" + file)
                        self.stp1 = self.tool.myPanel(self.panel)
                        self.hbox.Add(self.stp1, 7, wx.EXPAND | wx.LEFT |
wx.RIGHT | wx.BOTTOM, border=9)
                        self.apps[app_name] = self.stp1
                        self.show_flags[app_name] = False
                        self.stp1.Hide()
                    except:
                        print "You do not have access to the %s
App."%app_name

Anyone see a easy way to start this line of code in a new thread?
imp.load_source('myPanel_%s'%i, path + "\\" + file)

nope -- you'll need to re-factor your panels to use threads for the
process that they call. Good separation between the GUI and
doing-the-real-work code should make this fairly straightforward (call
it MVC, MVP or what have you).

HTH,
  -Chris

···

On Thu, Apr 11, 2013 at 7:19 AM, Jason Terhune <jasondashterhune@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

I have attached an example script.

Once the app button (Press to simulate long running process) is pressed, I want to be able to access the other buttons on the right.
Since I am importing the panels dynamically, I really don’t know what the processes are the app will call. This is the reason I would like to start the each new panel in a thread of its own. Is this possible?

Example.zip (5.41 KB)

Jason Terhune wrote:

Problem:
Everything works great until a long running process gets initiated by
one of the app panels. I would like to spawn each panel in a new
thread during import. Would this be possible?

Not if the app panels are creating windows that need to be integrated
with the main UI. The messages for a given window are always sent to
the thread that created the window. If that thread doesn't have a
message loop, then its messages will never get processed.

Can you need separate the UI part from the long-running computation part
in some way?

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Chris Barker - NOAA Federal wrote:

in a word, no. wx is not thread safe,

This is nitpicking, but technically speaking, that's not correct. This
implies that it is a problem wx could solve. wx is, in fact, mostly
thread safe. The issue is that wx relies on operating system user
interfaces that impose restrictions that wx must obey.

all GUI operation must be done
from the same thread, so you can't have different panels spawned
by/running in different threads

Well, you could, but that almost certainly results in a situation the
original poster did not intend.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

You could take a look at something I’m developing ref this post, in example2 i have sleep being called that does not lock up the gui. It works by sending signals that pass from the gui mainthread to a background thread pool, signals are sent back to the gui without either locking up. It might give you some ideas on how to tackle the problem in your code.

···

On Thursday, April 11, 2013 3:19:18 PM UTC+1, Jason Terhune wrote:

Overview:

I am using wxPython to make an “App store”. Basically, I am putting a
panel in a frame, adding a horizontal sizer to the panel, adding a column of buttons on the left, and then adding app panels on the right. The app panels are being imported dynamically from a shared directory. When the user clicks on a button I .hide() the current visible app then .show() the one the user clicked on.

Problem:

Everything works great until a long running process gets initiated by one of the app panels. I would like to spawn each panel in a new thread during import. Would this be possible? I don’t mind if the app panels get hung in a long running process. I would like for the buttons on the left and all the other apps to not freeze though. Unless they spawn a long running process.

This is the code I use to import the panels dynamically:

        for i, file in enumerate(os.listdir(path)):

            if file.endswith(".py"):      

                try:          

                    app_name = file[:file.rfind('.')]                                            

                    self.tool = imp.load_source('myPanel_%s'%i, path + "\\" + file)

                    self.stp1 = self.tool.myPanel(self.panel)

                    self.hbox.Add(self.stp1, 7, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=9)                

                    self.apps[app_name] = self.stp1

                    self.show_flags[app_name] = False

                    self.stp1.Hide()

                except:

                    print "You do not have access to the %s App."%app_name

Anyone see a easy way to start this line of code in a new thread?
imp.load_source(‘myPanel_%s’%

i, path + “\” + file)

Jason Terhune wrote:

Problem:

Everything works great until a long running process gets initiated by

one of the app panels. I would like to spawn each panel in a new

thread during import. Would this be possible?

Not if the app panels are creating windows that need to be integrated

with the main UI.

The app panels need to act independent of the main UI. Only the .show() and .hide() functions would need to “talk” to the app panels.

The messages for a given window are always sent to

the thread that created the window.

This is why I wanted the long running process to be initiated by the thread the panel is in. (Not the main UI)

If that thread doesn’t have a

message loop, then its messages will never get processed.

Can you need separate the UI part from the long-running computation part

in some way?

I was hoping to import the app panels, with unknown layouts and functionality, in a new thread from the main UI. I thought this might keep one of the apps from “freezing” the main UI since the app panel would be executing in a different thread than the main UI. This might be more complicated than I thought. :slight_smile:

···

On Thursday, April 11, 2013 12:52:13 PM UTC-5, Tim Roberts wrote:


Tim Roberts, ti...@probo.com

Providenza & Boekelheide, Inc.

right -- you can't do that, but you can have the Panel initiate a new
thread to do its real work in.

i.e. you put your threading code in the Panel plug-in, rather than in
your main app.

-Chris

···

On Thu, Apr 11, 2013 at 11:32 AM, Jason Terhune <jasondashterhune@gmail.com> wrote:

This is why I wanted the long running process to be initiated by the thread
the panel is in. (Not the main UI)

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

right – you can’t do that, but you can have the Panel initiate a new

thread to do its real work in.

i.e. you put your threading code in the Panel plug-in, rather than in

your main app.

I see what your saying, but I was hoping to avoid threading in the “plug-in” to avoid teaching the “plug-in” developers threading.
I was hoping to keep the threading an abstraction to the “plug-in” developers.

Thanks for your insight, Chris!

Jason Terhune wrote:

    right -- you can't do that, but you can have the Panel initiate a new
    thread to do its real work in.

    i.e. you put your threading code in the Panel plug-in, rather than in
    your main app.

I see what your saying, but I was hoping to avoid threading in the
"plug-in" to avoid teaching the "plug-in" developers threading.
I was hoping to keep the threading an abstraction to the "plug-in"
developers.

You can still abstract it by providing an API for it, like some startTask() method or something. Then you could still manage the threads in the framework if you need to, or change the implementation of how the tasks are run, or whatever.

···

--
Robin Dunn
Software Craftsman