Problems with PyDispatcher?

Hi All,

I am using pydispatcher to notify from a OnSelected() event in a
wxListCtrl to an object that manages the list of items, which will
then emit a signal to update all listeners.

However, the signal does not want to send inside the event hander!
When I send it in the main frame the signal is properly sent, but from
the OnSelected contect in wxPython, it is not.

This is the concept;

- User clicks on song (OnSelect is called)
- In OnSelect, signal SIG_SELECT_QRY is sent as a pydispatcher signal
- the song list should receive this, and send back SIG_SELECT_SONG when approved

The SIG_SELECT_QRY signal is not received by the song list when sent
inside the OnSelect handler. Is there by any chance a thread
difference or context difference when an event handler is fired in
wxPython?

Also, I read more about wx.lib.pubsub, is this one more robust against
these oddities? I like to have the one that is most robust in the
situation I described ..

Any ideas?
- Jorgen

Hi Josiah,

I appreciate your long explanation very much! I will see if I can get
rid of PyDispatcher and see if wx.lib.pubsub is going to work.

I was really looking foward to this architecture because it's more
elegant to update a listbox by using signals instead of tieing
everything in one big file. this way the intelligence of the listbox
stays in that component, and undo / redo mechanisms are easier to
implement ...

Thanks again!
- Jorgen

ยทยทยท

On 4/12/07, Josiah Carlson <jcarlson@uci.edu> wrote:

"Jorgen Bodde" <jorgen.maillist@gmail.com> wrote:
> I am using pydispatcher to notify from a OnSelected() event in a
> wxListCtrl to an object that manages the list of items, which will
> then emit a signal to update all listeners.
>
> However, the signal does not want to send inside the event hander!
> When I send it in the main frame the signal is properly sent, but from
> the OnSelected contect in wxPython, it is not.

I've heard about it not working in some cases. I don't know why.

> Also, I read more about wx.lib.pubsub, is this one more robust against
> these oddities? I like to have the one that is most robust in the
> situation I described ..

wx.lib.pubsub looks complicated, but aside from using weakrefs to make
sure that your 'event subscriptions' don't keep an object alive which
should otherwise be garbage collected, it is more or less equivalent to...

    callbacks = {}

    def subscribe(fcn, topic=''):
        topic = tuple(topic.split('.'))
        callbacks.setdefault(topic, ).append(fcn)

    def sendMessage(topic, data):
        topic = tuple(topic.split('.'))
        for i in xrange(len(topic)+1):
            for j in callbacks.get(topic[:i]):
                j(topic[:i], data)

That is to say, when you use
    wx.lib.pubsub.Publisher.sendMessage(topic, data)
Every function that is called is called *immediately*, one right after
the other. This can cause not insignificant issues with certain event
interactions, and may violate certain expectations that you or the GUI
may or may not have (especially if you are using threads).

If you find that using pubsub is breaking certain expectations that you
have, you could wrap all of your calls via wx.CallAfter. For example,
say that you have a function 'foo' that you want to call when a topic is
sent a message...

    #normally
    wx.lib.pubsub.Publisher.subscribe(foo, topic)

    #with wx.CallAfter
    cb = lambda *args, foo=foo : wx.CallAfter(foo, *args)

You could write a subscribe function that does this for you, but it
would negate all the work that pubsub goes to in order to allow for dead
objects to die. You could also patch the base _TopicTreeNode to do use
wx.CallAfter always...

    def sendMessage(self, message):
        """Send a message to our callables"""
        deliveryCount = 0
        for cb in self.__callables:
            listener = cb()
            if listener is not None:
                wx.CallAfter(listener, message)
                deliveryCount += 1
        return deliveryCount

    wx.lib.pubsub._TopicTreeNode.sendMessage = sendMessage

And this would behave very similarly to what you are currently doing,
except that it should always work.

- Josiah