Package NotificationFramework :: Module NotificationCenter
[show private | hide private]
[frames | no frames]

Module NotificationFramework.NotificationCenter

NotificationCenter is the central object of the framework --full documentation is here.

This module acts as a NotificationCenter.

Objects registers as listeners to some events/notifications.

Then, anytime a notification is posted to the central observers for this notification are automatically notified.

Listeners and callbacks

First at all, the Notification Center needs to have a mean to notify objects that a notification they are listening to was posted. To achieve this, objects should supply their reference, as well as a callback method at registration time (Note: by default only one callback is accepted per object; see discussion below).

The possible listeners are: class instances (types.InstanceType), code objects or functions (such as functions defined in a module). See method addObserver for full details ; we will focus in the following on class instances.

For listeners being class instances, callbacks' signature should minimally be one of these:

def callback(self, notification)
def callback(self, *arg)

Hence, any of the following signatures are okay:

def callback(self, notification, param1='param1')
def callback(self, notification, *arg)
def callback(self, notification, **kw)
etc.

Please note that the callback method must be supplied as a unbound method, e.g.: ObjectClass.callback.

When called by the NotificationCenter upon notification post, callback's parameter notification is a Notification instance.

Registration: Generic- and Specific- listeners

Object can register as "generic observers" or "specific observers".

Generic observers listens all notifications coming with a given name. They register themselves with:

NotificationCenter.addObserver(object, ObjectClass.method, 'NewMessage')

Generic observers will be notified each time a notification with that name is posted, whatever the accompaying object can be (including None).

Specific observers only listens notifications which have a given name and a given value. They register themselves with:

NotificationCenter.addObserver(object, ObjectClass.method,
                               'NewMessage', 'email')
NotificationCenter.addObserver(object, ObjectClass.method,
                               'NewMessage', 'news')
etc.      

Specific observers are only notified when a notification with these name and object is posted.

Registering more than one callback per object

By default, addObserver() checks that only one callback is registered per object; if you try to register a different one, you'll get a ValueError.

Of course, a single object can listen to multiple notifications. In that case, you'll probably register a given method, say, handleNotification(), dedicated to this task:

def handleNotification(self, notification):
  notification_name=notification.name()
  if notification_name == "NOTIFICATION_ONE":
    # code for notification one
  elif notification_name == "NOTIFICATION_TWO"
    # code for notification two
  else:
    # Unhandled notification

However, sometimes you do not want this; for example, you want to bind several methods of an object defined by a third-party module, and you do not want to modify its code. Registering multiple callbacks is possible when the environment variable NOTIFICATION_CENTER_MULTIPLE_CALLBACKS_PER_OBSERVER is defined and its value is not an empty string.

Important

This variable should be set prior to any import statement importing the NotificationCenter module, or it wont have any effect at all.

Example

bash
export NOTIFICATION_CENTER_MULTIPLE_CALLBACKS_PER_OBSERVER='y'
python
import os
os.environ['NOTIFICATION_CENTER_MULTIPLE_CALLBACKS_PER_OBSERVER']='y'
from NotificationFramework import NotificationCenter

Why is it not the default/only behaviour?

Handling multiple callbacks per object implies a performance penalty. You can test which are the consequences on your platform with the supplied script 'compare_perfs.py' in directory tests/ On my machine, postNotification() is about 2.4x slower when the handling of multiple callbacks per object is activated.

Notification names and objects

Notifications names should be strings, even if this is not enforced by the framework.

Notifications objects and info can be (almost: see below) everything. Restricting their type to existing python types will save you fighting against some strange behaviour, however, and should be sufficient for most situations --hopefully!

Zope: some important notes

TBD!!! In the meantime you can look at the code for methods observerCodeForZopePersistentObject() and observerCodeForZopeTemporaryObject(), and to tests/test_NotificationCenter.test_7_codeObjectObservers().

MT status: This library was designed to be MT-safe.

$Id: NotificationCenter.py 931 2004-06-22 18:51:06Z sbigaret $


Function Summary
  addObserver(observer, callback, notificationName, object, sameObserverRegistersOnce)
Adds the supplied observer to the list.
  observerCodeForZopePersistentObject(aZopePersistentObject)
  observerCodeForZopeTemporaryObject(aZopePersistentObject)
  postNotification(notificationName, object, info)
  removeObserver(observer, notificationName, object)
Unregisters the observer for the given notification.
  _listToNotifyForNotification(notification)
Private: do not call directly
  _observers()
PRIVATE, DO NOT CALL DIRECTLY

Function Details

addObserver(observer, callback, notificationName, object=None, sameObserverRegistersOnce=1)

Adds the supplied observer to the list.

Note that if the observer in a class' instance, it will be weakly referenced, thus this framework does not play any role in the garbage-collection of class' instances ; observers that are garbage-collected are automatically removed from the list of observers the first time they are supposed to receive a notification.

addObserver() raises ValueError when an attempt is made to register an object that was previously registered with a different callback than the one supplied. Please refer to the module's documentation for a complete discussion on this topic.

Parameters:
observer -
callback -

the observer object to be notified, and the method to call on that object when a given notification (see other parameters, below) is received. The following combinations of observer/callback are possible:

  • observer is a class instance (either a classic or a new-style instance): the callback should be a unbound method. For example, if class A's instance a is the observer, 'A.callMe' is ok (given that callMe is defined in class A). This unbound method should accept a Notification object as its second parameter (the first parameter being 'self').

  • observer is a code object (see python-core's module 'code'). In that case, the code object must define a 'observer_object' variable: this object is the one that will be notified. In this situation, the callback should a valid method accepting that 'observer_object' as its first parameter, and a Notification object as its second argument (e.g., if 'observer_object' is an class instance, the callback can be an unbound method defined in the corresponding class).

    Such an object can be constructed that way (inspired from tests.test_NotificationCenter, to which you can have a look as well):

    import code
    code=code.compile_command('import aModule;'+
                              'observer_object=aModule.anObject')
    
  • observer is None: the callback must be of type 'types.FunctionType'

notificationName -
object - identifies the notification the observer listens to. The notificationName is mandatory and is usually a string. The object is optional. If provided, the observer will only be notified when a notification is posted with the same name and accompanying object. If omitted or None,the observer will be notified each time a notification with the correspoinding notificationName is posted (whatever the accompanying object can be in the posted notification).
sameObserverRegistersOnce - if omitted or if it evaluates to a true value, the same observer will only be added once for the notification identified by (notificationName, object) (if the observer is None, replace observer with callback in the previous sentence) ; note that a notification with an accompanying object being None and another one whose accompanying object is not None are always considered different, hence in this case this option has obviously no effect. If this parameter evaluates to a false value, then the same observer can be multiply registered --in this case, such an observer's callback should be ready to answer more than once to a single notification post, and should be removed as many times as it was registered.

observerCodeForZopePersistentObject(aZopePersistentObject)

observerCodeForZopeTemporaryObject(aZopePersistentObject)

removeObserver(observer, notificationName=None, object=None)

Unregisters the observer for the given notification. Regarding the fact that an observer can be multiply registered for a single Notification (see: addObserver()), this method removes one and only one of the registered occurences except when both notificationName and object are omitted or None: see below.

Silently returns if 'observer' is not registered.

Parameters:
observer - the observer object to unregister
notificationName -
object - these parameters identify the Notification for which the observer should be unregistered. If both are omitted or are equal to None, then the observer is completely removed from all the lists of observers. This includes all occurrences of 'observer' if it has been multiply registered.

_listToNotifyForNotification(notification)

Private: do not call directly

_observers()

PRIVATE, DO NOT CALL DIRECTLY

Generated by Epydoc 2.1 on Sat Mar 4 13:36:33 2006 http://epydoc.sf.net