Another wxPython design question; MVC, or...?

I need to settle on a design for a project, and just use it…
Currently started with MVC and variants, but am looking at Observer patterns now, like this nice article
https://www.packtpub.com/article/wxpython-design-approaches-techniques
Merging the View and Controller seems popular too.
The application is an MDI data collector and presenter, not so different than Audacity. View is created with Boa, but all bound event methods are off in controller modules (GUI can be messed with without touching controller code & vice-versa).
Data, once collected by the worker thread, can only be passed by reference - actually moving it (via pubSub etc.) is out of the question due to size and speed.

Current thought:

  • start a model wxThread that does data collecting to numpy arrays, and which checks via pubsub in between blocks of data collected for messages. The thread is a producer of data, and publishes ‘data ready’ messages (or events).
  • enter mainloop
  • events respond to user demands for configuration (pub’d to model), plot creation (in view), start/stop etc. and run in the main thread, consuming data from the model thread’s numpy array.

Experiences with simple wxEvents vs. pubSub?
Thread, threading, or wxThread?
Merge the View and Controller ?

Comments, please?

Ray

I need to settle on a design for a project, and just use it...
Currently started with MVC and variants, but am looking at Observer
patterns now, like this nice article
Search | Packt Subscription
Merging the View and Controller seems popular too.
The application is an MDI data collector and presenter, not so different
than Audacity. View is created with Boa, but all bound event methods are
off in controller modules (GUI can be messed with without touching
controller code & vice-versa).
Data, once collected by the worker thread, can only be passed by
reference - actually moving it (via pubSub etc.) is out of the question
due to size and speed.

Current thought:
- start a model wxThread that does data collecting to numpy arrays, and
which checks via pubsub in between blocks of data collected for
messages. The thread is a producer of data, and publishes 'data ready'
messages (or events).
- enter mainloop
- events respond to user demands for configuration (pub'd to model),
plot creation (in view), start/stop etc. and run in the main thread,
consuming data from the model thread's numpy array.

Experiences with simple wxEvents vs. pubSub?

Pubsub is much more versatile. Events can only travel one direction (up the containment hierarchy) where pubsub messages can be handled anywhere in your app, and easily in any number of anywheres.

Thread, threading, or wxThread?

The only part of wxThread that is wrapped is the IsMain static method. Python's threading module is much better and so there isn't any need to have wxThread, other than to be able to find out if the current thread is the one that wx considers the main thread.

Merge the View and Controller ?

That is entirely subjective and really depends on if that fits your brain okay and also on the needs of the application. It may even be that some other pattern fits the needs of the project better, you just need to figure out what makes the most sense and then do it.

In case you haven't seen it yet there is some other design pattern stuff here: wxPython Patterns - wxPyWiki. There is also an implementation of a framework for the DocView pattern in the wx.lib.docview and wx.lib.pydocview modules.

···

On 6/14/11 3:14 PM, rjsdotorg wrote:

--
Robin Dunn
Software Craftsman

Thanks Robin,
I had seen the wiki, and I have your book; and, DocView does not seem right for this app.
I jin’d up a little wx demo app that demonstrates MVC, threads, and pubsub with Boa,
http://rjs.org/test/kwargs_threaded.zip
but I seem to need a wx.Yield() in the while started by a listener method. This seems undesirable in a Model that should not are about a GUI.
The problem is that since pub.sendMessage does not return until the listener does ("it does garantee that upon return from the
send operation, all listeners have handled the message and returned
without exception."
), without yield in the while loop the GUI stops responding. What is the best way to handle this otherwise? The Controller sending a message should not have to wait for a Model’s response, but, I want to initiate the data collection method/loop in the other thread by sending the Model a message.
One way that works (tested) is to have the Model’s subscribe() call a simple method which then starts the psOnStartData() method in yet another thread, but should that be necessary?
The example could be informative for coders, but needs some tweaks I’d think.

···

class Frame1Controller:

def OnButtonStartButton(self, event):
#self.prnt.model.psOnStartData()
print 1
pub.sendMessage(“controls.start_data”)
print 2

class DataCollector(threading.Thread): #Model
def init(self, name=“model”):
self.myData = numpy.zeros((1000000,))
threading.Thread.init(self)
self.started = False
def run(self):
## subscribe to all “start_data” messages from the Controller
subscribe(self.psOnStartData, “controls.start_data”)
subscribe(self.psOnStopData, “controls.stop_data”)
def psOnStartData(self):
print "Model Started… "
self.started = True
## create data and send messages to whoever
t0 = time.clock()
while self.started:
self.myData[0] += 1
sendMessage(“data.new_data_ready”, d = self.myData)
wx.Yield()
e = (time.clock() - t0 -) / self.myData[0]
print “Model Stopped.”
sendMessage(“data.meta_data”, s = e)

Thanks Robin,
I had seen the wiki, and I have your book; and, DocView does not seem
right for this app.
I jin'd up a little wx demo app that demonstrates MVC, threads, and
pubsub with Boa,
http://rjs.org/test/kwargs_threaded.zip
but I seem to need a wx.Yield() in the while started by a listener
method. This seems undesirable in a Model that should not are about a GUI.

Pubsub does not automatically cross thread boundaries when subscribers subscribe in a different thread than where the message is published. You'll have to help it to do that. In your example the DataCollector thread terminates at the end of the run() method, and the calls to the subscribed methods for the published messages are actually happening in the context of the GUI thread, which is why you have to call wx.Yield to prevent it from blocking.

The problem is that since pub.sendMessage does not return until the
listener does ("/it does garantee that upon return from the send
operation, all listeners have handled the message and returned without
exception."/), without yield in the while loop the GUI stops responding.
What is the best way to handle this otherwise? The Controller sending a
message should not have to wait for a Model's response, but, I want to
initiate the data collection method/loop in the other thread by sending
the Model a message.
One way that works (tested) is to have the Model's subscribe() call a
simple method which then starts the psOnStartData() method in yet
another thread, but should that be necessary?
The example could be informative for coders, but needs some tweaks I'd
think.

One approach that comes to mind is to have the thread waiting in a loop (in the run() method) for an item to be added to a Queue. The methods subscribed to the pubsub topic will expect to be running in the gui thread and will simply create an object to add to that Queue and then will return. When the thread is woke up by the item being added to the Queue then it can fetch the obj, do whatever is needed to process it, and then fetch or wait for the next item to be added to the Queue object.

···

On 6/17/11 3:39 PM, Ray S wrote:

--
Robin Dunn
Software Craftsman

> Thanks Robin,
> I had seen the wiki, and I have your book; and, DocView does not seem
> right for this app.
> I jin'd up a little wx demo app that demonstrates MVC, threads, and
> pubsub with Boa,
>http://rjs.org/test/kwargs_threaded.zip
> but I seem to need a wx.Yield() in the while started by a listener
> method. This seems undesirable in a Model that should not are about a GUI.

Pubsub does not automatically cross thread boundaries when subscribers
subscribe in a different thread than where the message is published.
You'll have to help it to do that. In your example the DataCollector
thread terminates at the end of the run() method, and the calls to the
subscribed methods for the published messages are actually happening in
the context of the GUI thread, which is why you have to call wx.Yield to
prevent it from blocking.

In this case it might be just as well to init the Model in the App
thread, and call the psOnStartData() method in the new thread. The
assumption is that the data method is I/O intensive and would benefit
from threading. I had considered forking a process and using IPC and
shared memory before testing Enthought's MKL enabled distro, but I
think I would prefer threading.
I want to avoid PostEvent() use since that requires a wx app to be
connected.

> The problem is that since pub.sendMessage does not return until the
> listener does ("/it does garantee that upon return from the send
> operation, all listeners have handled the message and returned without
> exception."/), without yield in the while loop the GUI stops responding.
> What is the best way to handle this otherwise? The Controller sending a
> message should not have to wait for a Model's response, but, I want to
> initiate the data collection method/loop in the other thread by sending
> the Model a message.
> One way that works (tested) is to have the Model's subscribe() call a
> simple method which then starts the psOnStartData() method in yet
> another thread, but should that be necessary?
> The example could be informative for coders, but needs some tweaks I'd
> think.

One approach that comes to mind is to have the thread waiting in a loop
(in the run() method) for an item to be added to a Queue. The methods
subscribed to the pubsub topic will expect to be running in the gui
thread and will simply create an object to add to that Queue and then
will return. When the thread is woke up by the item being added to the
Queue then it can fetch the obj, do whatever is needed to process it,
and then fetch or wait for the next item to be added to the Queue object.

I could probably have the run() poll the Queue and sleep()

Another option is I'll allow the Controller to call the Model's API
directly, rather than simply signal. This still does not tie the V-C
to wx so it seems OK. It is also conceptually simpler.

I'm also looking at
http://pydispatcher.sourceforge.net/
although I haven't seen much example code other than
http://wxpython-users.1045709.n5.nabble.com/wxPython-signals-tt2330794.html#a2330806\#none,
and indications are that it will not cross threads either.

More tests to do Monday...

Thanks,
Ray

···

On Jun 18, 12:13 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 6/17/11 3:39 PM, Ray S wrote: