notification.py
142 lines
| 4.5 KiB
| text/x-python
|
PythonLexer
Barry Wark
|
r1410 | # encoding: utf-8 | ||
Brian Granger
|
r2302 | """ | ||
The IPython Core Notification Center. | ||||
Barry Wark
|
r1410 | |||
Barry Wark
|
r1443 | See docs/source/development/notification_blueprint.txt for an overview of the | ||
Barry Wark
|
r1410 | notification module. | ||
Brian Granger
|
r2302 | |||
Authors: | ||||
* Barry Wark | ||||
* Brian Granger | ||||
Barry Wark
|
r1410 | """ | ||
#----------------------------------------------------------------------------- | ||||
Brian Granger
|
r2302 | # Copyright (C) 2008-2009 The IPython Development Team | ||
# | ||||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Code | ||||
Barry Wark
|
r1410 | #----------------------------------------------------------------------------- | ||
Brian Granger
|
r2302 | |||
class NotificationError(Exception): | ||||
pass | ||||
Barry Wark
|
r1410 | |||
class NotificationCenter(object): | ||||
Brian Granger
|
r2302 | """Synchronous notification center. | ||
Barry Wark
|
r1412 | |||
Fernando Perez
|
r2109 | Examples | ||
-------- | ||||
Brian Granger
|
r2302 | Here is a simple example of how to use this:: | ||
MinRK
|
r3520 | import IPython.util.notification as notification | ||
Brian Granger
|
r2302 | def callback(ntype, theSender, args={}): | ||
print ntype,theSender,args | ||||
notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None) | ||||
notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS | ||||
NOTIFICATION_TYPE ... | ||||
Barry Wark
|
r1412 | """ | ||
Barry Wark
|
r1410 | def __init__(self): | ||
super(NotificationCenter, self).__init__() | ||||
Barry Wark
|
r1411 | self._init_observers() | ||
Brian Granger
|
r2302 | |||
Barry Wark
|
r1411 | def _init_observers(self): | ||
"""Initialize observer storage""" | ||||
Brian Granger
|
r2302 | |||
Barry Wark
|
r1443 | self.registered_types = set() #set of types that are observed | ||
self.registered_senders = set() #set of senders that are observed | ||||
Barry Wark
|
r1410 | self.observers = {} #map (type,sender) => callback (callable) | ||
Fernando Perez
|
r2109 | |||
Brian Granger
|
r2302 | def post_notification(self, ntype, sender, *args, **kwargs): | ||
"""Post notification to all registered observers. | ||||
The registered callback will be called as:: | ||||
callback(ntype, sender, *args, **kwargs) | ||||
Parameters | ||||
---------- | ||||
ntype : hashable | ||||
The notification type. | ||||
sender : hashable | ||||
The object sending the notification. | ||||
*args : tuple | ||||
The positional arguments to be passed to the callback. | ||||
**kwargs : dict | ||||
The keyword argument to be passed to the callback. | ||||
Fernando Perez
|
r2109 | |||
Brian Granger
|
r2302 | Notes | ||
----- | ||||
Barry Wark
|
r1410 | * If no registered observers, performance is O(1). | ||
* Notificaiton order is undefined. | ||||
* Notifications are posted synchronously. | ||||
""" | ||||
Brian Granger
|
r2302 | |||
if(ntype==None or sender==None): | ||||
raise NotificationError( | ||||
"Notification type and sender are required.") | ||||
Barry Wark
|
r1410 | # If there are no registered observers for the type/sender pair | ||
Brian Granger
|
r2302 | if((ntype not in self.registered_types and | ||
Barry Wark
|
r1443 | None not in self.registered_types) or | ||
(sender not in self.registered_senders and | ||||
None not in self.registered_senders)): | ||||
Barry Wark
|
r1410 | return | ||
Brian Granger
|
r2302 | |||
for o in self._observers_for_notification(ntype, sender): | ||||
o(ntype, sender, *args, **kwargs) | ||||
def _observers_for_notification(self, ntype, sender): | ||||
Barry Wark
|
r1411 | """Find all registered observers that should recieve notification""" | ||
Brian Granger
|
r2302 | |||
Barry Wark
|
r1411 | keys = ( | ||
Brian Granger
|
r2302 | (ntype,sender), | ||
(ntype, None), | ||||
(None, sender), | ||||
(None,None) | ||||
) | ||||
Barry Wark
|
r1411 | obs = set() | ||
for k in keys: | ||||
obs.update(self.observers.get(k, set())) | ||||
Brian Granger
|
r2302 | |||
Barry Wark
|
r1411 | return obs | ||
Brian Granger
|
r2302 | |||
def add_observer(self, callback, ntype, sender): | ||||
Barry Wark
|
r1410 | """Add an observer callback to this notification center. | ||
The given callback will be called upon posting of notifications of | ||||
Brian Granger
|
r2302 | the given type/sender and will receive any additional arguments passed | ||
Barry Wark
|
r1410 | to post_notification. | ||
Parameters | ||||
---------- | ||||
Brian Granger
|
r2302 | callback : callable | ||
The callable that will be called by :meth:`post_notification` | ||||
as ``callback(ntype, sender, *args, **kwargs) | ||||
ntype : hashable | ||||
Barry Wark
|
r1410 | The notification type. If None, all notifications from sender | ||
will be posted. | ||||
sender : hashable | ||||
Brian Granger
|
r2302 | The notification sender. If None, all notifications of ntype | ||
Barry Wark
|
r1410 | will be posted. | ||
""" | ||||
Barry Wark
|
r1411 | assert(callback != None) | ||
Brian Granger
|
r2302 | self.registered_types.add(ntype) | ||
Barry Wark
|
r1443 | self.registered_senders.add(sender) | ||
Brian Granger
|
r2302 | self.observers.setdefault((ntype,sender), set()).add(callback) | ||
Barry Wark
|
r1411 | |||
def remove_all_observers(self): | ||||
"""Removes all observers from this notification center""" | ||||
self._init_observers() | ||||
Barry Wark
|
r1410 | |||
Brian Granger
|
r2302 | shared_center = NotificationCenter() | ||