pubsub ready for testing

I have a new version of pubsub ready for testing for integration to next wxPython. I have used it in a couple of my legacy apps and it works out of the box without changes required, but it would be nice to get a larger sample set :slight_smile:

You can get it from download site or using easy_install pypubsub or (probably best option) SVN (URL to use).

For testing with your existing pubsub-based applications, you will have to add two lines in your main script:

import pubsubconf

pubsubconf.setMsgProtocol(‘dataArg’)

New applications don’t need this, unless you absolutely want to use the “old” messaging protocol.

Mostly I’d like to find out if the new version, with above two lines, breaks any applications, but any feedback welcome (posting to pypubsub group not necessary but would be much appreciated).

Regards,

Oliver

oliver wrote:

I have a new version of pubsub ready for testing for integration to next wxPython.

great news!

This reminds me of a pubsub question I've been pondering:

A while back we had a big discussion about messaging and pubsub, spawned by someone asking something like:

How do I subscribe to a message from a particular publisher?

The argument given in response by a few folks (including me!) is that you shouldn't want to do that -- you should only care about what kind of message it is, not where it came from.

However, here's my use case and question:

I'm planning on doing some re-working of wx/lib/floatcanvas to use pubsub. I want to be able to send messages out like:

  The GUI mode of the canvas has changed.
  The Canvas Bounding Box has changed
  The Canvas Scale has changed

This will allow me to do things like reset toolbars, scrollbars and the like, without the Canvas needing to know how its parent is set up, and without the user having to explicitly update the whole GUI when a change to the canvas is made.

However: There could be more than one Canvas in an app. In that case, if Canvas_A's Bounding Box changes, the scrollbars associated with Canvas_A need to update, but the scrollbars associated with Canvas_B don't.

How do I handle that?

thanks,

-Chris

···

--
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

[sorry this is a bit longer than intended]

Well, a message is basically an event. The topic is the event type. Therefore I would recommend making the event types (topic names) relate to what’s happening on the floatcanvas (e.g., ‘floatcanvasChange.newScale’, ‘floatcanvasChange.newBBox’, etc), and the event data carry a reference to the originator (name, id, actual reference, etc). Note that this is similar to the way events are implemented in wx, MFC, etc.

There are surely cases where you could have an event type be specific to the originator, e.g. ‘floatcanvasChange.newScale.canvasA’. But this is likely a hack: every level of the topic tree should probably make sense as an event:. For instance ‘floatcanvasChange’ makes sense as an event type, and so does ‘floatcanvasChange.newScale’ which says what type of change occurred. But what does an event ‘floatcanvasChange.newScale.canvasA’ mean? CanvasA is not an event. If you say that it means ‘it is a change specific to canvasA’ then again canvasA ought to be data for the event, not part of the event type.

Really subtopics ought to be more specific events, so a subtopic of newScale could be ‘scaleIncreased’, ‘scaleDecreased’ etc. So you would have ‘floatcanvas.newScale.scaleIncreased’ and ‘floatcanvas.newScale.scaleDecreased’, and most listeners would not care whether the change was increase or decrease so they would just subscribe to ‘floatcanvas.newScale’, but some might just be interested in increases (e.g., an overlay that shows an arrow going up if there was an increase).

That being said, it sounds like you are really looking for an Observer pattern rather than a publish subscribe pattern. Would it make sense that more than one object listen to changes to your canvas bbox? Probably. Would it happen often? Probably not. But if it’s something you want to support, then Observer is not adequate and publish-subscribe is what you need. However, there isn’t much difference between an observer pattern and a pubsub-with-originator pattern. An observer would register to an object for certain types of changes. With pubsub, you would register for certain types of changes that are specific to an object.

So in the end maybe purity is getting in the way of JUST HAVING FUN using the stuff!! :slight_smile:

Thoughts?

Oliver

···

On Thu, Oct 23, 2008 at 1:25 PM, Christopher Barker Chris.Barker@noaa.gov wrote:

oliver wrote:

I have a new version of pubsub ready for testing for integration to next wxPython.

great news!

[
]

This will allow me to do things like reset toolbars, scrollbars and the like, without the Canvas needing to know how its parent is set up, and without the user having to explicitly update the whole GUI when a change to the canvas is made.

However: There could be more than one Canvas in an app. In that case, if Canvas_A’s Bounding Box changes, the scrollbars associated with Canvas_A need to update, but the scrollbars associated with Canvas_B don’t.

How do I handle that?

Christopher Barker wrote:

oliver wrote:

I have a new version of pubsub ready for testing for integration to next wxPython.

great news!

This reminds me of a pubsub question I've been pondering:

A while back we had a big discussion about messaging and pubsub, spawned by someone asking something like:

How do I subscribe to a message from a particular publisher?

The argument given in response by a few folks (including me!) is that you shouldn't want to do that -- you should only care about what kind of message it is, not where it came from.

However, here's my use case and question:

I'm planning on doing some re-working of wx/lib/floatcanvas to use pubsub. I want to be able to send messages out like:

The GUI mode of the canvas has changed.
The Canvas Bounding Box has changed
The Canvas Scale has changed

This will allow me to do things like reset toolbars, scrollbars and the like, without the Canvas needing to know how its parent is set up, and without the user having to explicitly update the whole GUI when a change to the canvas is made.

However: There could be more than one Canvas in an app. In that case, if Canvas_A's Bounding Box changes, the scrollbars associated with Canvas_A need to update, but the scrollbars associated with Canvas_B don't.

How do I handle that?

Since pubsub allows for hierarchical topics, you could make a canvas identifier be part of the topic that is published, something like this: "BoundingBoxChanged.Canvas-A" The subscribers that want to listen for messages from all canvases can subscribe to "BoundingBoxChanged" and those that just care about Canvas-A can use the full topic.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

To me using pubsub for this sort of thing just doesn't smell right.
For GUI apps like this a Signal/Slots observer pattern is a much
closer fit for what you're after IMO.
It doesn't smell right to me because after you establish the
connection that ObjectA wants to listen to something about ObjectB,
why should they have to go through a 3rd party (a global one, no less)
to communicate? With the hierarchical message suggestion, if you're
having ObjectA include a specific identifier for ObjectB in the
message subject, then presumably ObjectA already knows something about
ObjectB specifically, and can probably get a reference to ObjectB in
order to establish a direct signal/slot or Observer connection.
Anyway it my feeling of an ObjectA wants to know something about
ObjectB then it can usually can get a reference to ObjectB. The
reverse isn't necessary. Situations where ObjectA needs to know about
any change that happens anywhere are rare. Like the specific case at
hand -- what use would an object have for knowing about every bounding
box in the app? The opposite is probably more common, wanting to
know about every message from a given object.

Pubsub really only makes sense to me in the case where you have some
kind of global state.

Those are my thoughts after trying to get Pubsub to work as a general
GUI notification system.
I ended up using a sligtly modified version of Patrick Chasco's
signals.py. (Self-managing, maintenance-free Signals implementation « Python recipes « ActiveState Code)

--bb

···

On Fri, Oct 24, 2008 at 10:55 AM, Robin Dunn <robin@alldunn.com> wrote:

Christopher Barker wrote:

oliver wrote:

I have a new version of pubsub ready for testing for integration to next
wxPython.

great news!

This reminds me of a pubsub question I've been pondering:

A while back we had a big discussion about messaging and pubsub, spawned
by someone asking something like:

How do I subscribe to a message from a particular publisher?

The argument given in response by a few folks (including me!) is that you
shouldn't want to do that -- you should only care about what kind of message
it is, not where it came from.

However, here's my use case and question:

I'm planning on doing some re-working of wx/lib/floatcanvas to use pubsub.
I want to be able to send messages out like:

The GUI mode of the canvas has changed.
The Canvas Bounding Box has changed
The Canvas Scale has changed

This will allow me to do things like reset toolbars, scrollbars and the
like, without the Canvas needing to know how its parent is set up, and
without the user having to explicitly update the whole GUI when a change to
the canvas is made.

However: There could be more than one Canvas in an app. In that case, if
Canvas_A's Bounding Box changes, the scrollbars associated with Canvas_A
need to update, but the scrollbars associated with Canvas_B don't.

How do I handle that?

Since pubsub allows for hierarchical topics, you could make a canvas
identifier be part of the topic that is published, something like this:
"BoundingBoxChanged.Canvas-A" The subscribers that want to listen for
messages from all canvases can subscribe to "BoundingBoxChanged" and those
that just care about Canvas-A can use the full topic.

oliver wrote:

However: There could be more than one Canvas in an app. In that case,
if Canvas_A's Bounding Box changes, the scrollbars associated with
Canvas_A need to update, but the scrollbars associated with Canvas_B
don't.

How do I handle that?

[sorry this is a bit longer than intended]

not that long, and very helpful.

Well, a message is basically an event. The topic is the event type. Therefore I would recommend making the event types (topic names)
relate to what's happening on the floatcanvas (e.g., 'floatcanvasChange.newScale', 'floatcanvasChange.newBBox', etc), and
the event data carry a reference to the originator (name, id, actual
reference, etc).

So this would mean that, for instance, all the scrollbars would
subscribe to the floatcanvasChange.newBBox event, then look at the event
data to see if it's the Canvas it cares about. That seems like I'm
putting the same code (event.data.sourcecanvas is ThisCanvas) in lots of
places -- that scrollbar is never going to want to know about what any
other Canvas is doing.

Note that this is similar to the way events are implemented in wx.

well, sort of. IN the wx case, you bind to an event from a particular
source. The way I write my code, I rarely need to check what source an
event came from, and in any case, it's not required.

There are surely cases where you could have an event type be specific
to the originator, e.g. 'floatcanvasChange.newScale.canvasA'. But
this is likely a hack: every level of the topic tree should probably
make sense as an event:.

maybe, but this seems like a purity issue.

Really subtopics ought to be more specific events, so a subtopic of newScale could be 'scaleIncreased', 'scaleDecreased' etc. So you
would have 'floatcanvas.newScale.scaleIncreased' and 'floatcanvas.newScale.scaleDecreased', and most listeners would not
care whether the change was increase or decrease so they would just
subscribe to 'floatcanvas.newScale', but some might just be
interested in increases (e.g., an overlay that shows an arrow going
up if there was an increase).

Thanks -- this does help me "get" pubsub better.

That being said, it sounds like you are really looking for an
Observer pattern rather than a publish subscribe pattern. Would it
make sense that more than one object listen to changes to your canvas
bbox?

yes.

Would it happen often?

Actually, I think it would be pretty common in that case, and many others.

Probably not. But if it's something you want to support, then
Observer is not adequate

why not? can't multiple objects Observe the same source?

So in the end maybe purity is getting in the way of JUST HAVING FUN using the stuff!! :slight_smile:

That's true -- I need to pick something, many approaches would work.

Robin Dunn wrote:

Since pubsub allows for hierarchical topics, you could make a canvas
identifier be part of the topic that is published, something like
this: "BoundingBoxChanged.Canvas-A" The subscribers that want to
listen for messages from all canvases can subscribe to
"BoundingBoxChanged" and those that just care about Canvas-A can use
the full topic.

and I could still put data in that identified the source, etc if I
wanted. Could I do:

"Canvas-A.BoundingBoxChanged"

somehow that feels more natural, but then I might need to able to
subscribe to : "*.BoundingBoxChanged" -- can you do that?

Bill Baxter wrote:

To me using pubsub for this sort of thing just doesn't smell right.

I see what you mean. However, this is integrated into apps that might be
using MVC-type structure, and in that case, pubsub makes sense -- I want
to be able to sent out a message from the model, and monitor such
messages with little connection between them.

why should they have to go through a 3rd party (a global one, no
less) to communicate?

I think this is my question, too: I avoid global everything else, why
use global events? If the is only one of each kind of object in app, it
makes little difference, but if there are multiple instances of things,
you then need separate them out again by hand.

what use would an object have for knowing about every bounding box in
the app? The opposite is probably more common, wanting to know
about every message from a given object.

exactly.

Pubsub really only makes sense to me in the case where you have some kind of global state.

yup -- it seems like a great way to handle application global messaging,
but there really isn't much of that. I was hoping to use the same thing
everywhere, though -- how may messaging systems do you want to use?

oliver wrote:

However, there isn't much difference between an observer pattern and
a pubsub-with-originator pattern.

exactly -- though what I want is the originator to be handles for me, without me having to check it in every method that subscribes to a message.

I ended up using a slightly modified version of Patrick Chasco's signals.py. (Self-managing, maintenance-free Signals implementation « Python recipes « ActiveState Code)

thanks for the link.

I can research this for myself, but while we're on the topic:

what is the difference between signals and regular old wx events? It seems that with wx events, Windows raise events, and you can tell other objects to watch for particular events from particular windows -- how are signals different?

I'd rather not have FloatCanvas depend on anything more, so I'm leaning toward using regular wx events for FloatCanvas changes, and maybe pubsub at the application level.

-Chris

···

On Thu, Oct 23, 2008 at 1:25 PM, Christopher Barker > <Chris.Barker@noaa.gov <mailto:Chris.Barker@noaa.gov>> 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

and I could still put data in that identified the source, etc if I

wanted. Could I do:

“Canvas-A.BoundingBoxChanged”

somehow that feels more natural, but then I might need to able to

subscribe to : “*.BoundingBoxChanged” – can you do that?

No. This is particularly tricky because even if you could resolve ‘*’ at registration time, you would need heavy work to make sure new base topics are also included if created later (so if A.E and B.E exist at subscription time, your listener could get both; but if C.E topic gets created after that, your listener wouldn’t get C.E messages).

The other problem I have found with a topic like “Canvas-A.BoundingBoxChanged” is that it tends toward an object-based topic hierarchy; for just canvas this is not bad but for more complex components (as in, more deeply nested) you quickly end up with a topic tree that mimics your application implementation structure, and any kind of refactoring is a royal pain to make. Whereas, event types tend to change far less (another reason not to include the originator in the event type because pretty soon you want an event from a sub-component inside your canvas, which then needs the canvas name that it belongs to
 sometimes more coupling that you want).

Also, when you put your canvas in an application, it is likely the user would want to have a parent topic, e.g. app.somePage.canvasA
 but your canvas doesn’t know the parent topic. You could work around that by taking an optional argument at construction, the base topic, and adding to that, that also allows you to know whether user even wants to use pubsub messaging with your canvas:

class Canvas:

def init(self, parentTopic=None):

if parentTopic is not None:

topicName = parentTopic.getName() + ‘.canvas’

topic = pub.newTopic(topicName, 
)

self.psTopicName = topicName # or self.psTopic = topic

def changeBBox(self):




pub.sendMessage(self.psTopicName + ‘.bboxChanged’, 
)

Bill Baxter wrote:

To me using pubsub for this sort of thing just doesn’t smell right.

I see what you mean. However, this is integrated into apps that might be

using MVC-type structure, and in that case, pubsub makes sense – I want

to be able to sent out a message from the model, and monitor such

messages with little connection between them.

why should they have to go through a 3rd party (a global one, no

less) to communicate?

I think this is my question, too: I avoid global everything else, why

use global events? If the is only one of each kind of object in app, it

makes little difference, but if there are multiple instances of things,

you then need separate them out again by hand.

Seems to me that if you don’t want canvas to know anything about the recipient (API etc) then you have to go global since you don’t know in what scope your canvas will be used. Alternately, if you want Observers of your canvas, then why not just accept an interface object that you call whenever some event happens? This way you don’t depend on anything external:

class IChangeHandler:

def onChange(self, data): pass

class Canvas:

def registerHandler(self, handler, eventType):

self.handlers[eventType].append(handler)

def changeBBox(self):




notifyHandlers(‘bbox’, data)

def notifyHandlers(self, eventType, data):

for handler in self.handlers[eventType]:

handler.onChangeNotify(data)

Notice that if you factor out the registerHandler and notifyHandlers methods into an Observable base class that any of your classes could derive from, you have your own flavor of signals.py.

Oliver

···

On Fri, Oct 24, 2008 at 2:57 PM, Christopher Barker Chris.Barker@noaa.gov wrote: