##// END OF EJS Templates
fixed None for type/sender
Barry Wark -
Show More
@@ -1,85 +1,110 b''
1 1 # encoding: utf-8
2 2
3 3 """The IPython Core Notification Center.
4 4
5 5 See docs/blueprints/notification_blueprint.txt for an overview of the
6 6 notification module.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18
19 19 class NotificationCenter(object):
20 20 """Synchronous notification center"""
21 21 def __init__(self):
22 22 super(NotificationCenter, self).__init__()
23 self._init_observers()
24
25
26 def _init_observers(self):
27 """Initialize observer storage"""
28
23 29 self.registeredTypes = set() #set of types that are observed
24 30 self.registeredSenders = set() #set of senders that are observed
25 31 self.observers = {} #map (type,sender) => callback (callable)
26 32
27 33
28 34 def post_notification(self, theType, sender, **kwargs):
29 35 """Post notification (type,sender,**kwargs) to all registered
30 36 observers.
31 37
32 38 Implementation
33 39 --------------
34 40 * If no registered observers, performance is O(1).
35 41 * Notificaiton order is undefined.
36 42 * Notifications are posted synchronously.
37 43 """
38 44
39 45 if(theType==None or sender==None):
40 46 raise Exception("NotificationCenter.post_notification requires \
41 47 type and sender.")
42 48
43 49 # If there are no registered observers for the type/sender pair
44 if((theType not in self.registeredTypes) or
45 (sender not in self.registeredSenders)):
50 if((theType not in self.registeredTypes and None not in self.registeredTypes) or
51 (sender not in self.registeredSenders and None not in self.registeredSenders)):
52 print theType,sender,self.registeredTypes,self.registeredSenders
46 53 return
47 54
48 keys = ((theType,sender), (None, sender), (theType, None), (None,None))
49 observers = set()
50 for k in keys:
51 observers.update(self.observers.get(k, set()))
52
53 for o in observers:
55 for o in self._observers_for_notification(theType, sender):
54 56 o(theType, sender, args=kwargs)
57
58
59 def _observers_for_notification(self, theType, sender):
60 """Find all registered observers that should recieve notification"""
55 61
62 keys = (
63 (theType,sender),
64 (theType, None),
65 (None, sender),
66 (None,None)
67 )
68
69
70 obs = set()
71 for k in keys:
72 obs.update(self.observers.get(k, set()))
73
74 return obs
56 75
57 def add_observer(self, observerCallback, theType, sender):
76
77 def add_observer(self, callback, theType, sender):
58 78 """Add an observer callback to this notification center.
59 79
60 80 The given callback will be called upon posting of notifications of
61 81 the given type/sender and will receive any additional kwargs passed
62 82 to post_notification.
63 83
64 84 Parameters
65 85 ----------
66 86 observerCallback : callable
67 87 Callable. Must take at least two arguments::
68 88 observerCallback(type, sender, args={})
69 89
70 90 theType : hashable
71 91 The notification type. If None, all notifications from sender
72 92 will be posted.
73 93
74 94 sender : hashable
75 95 The notification sender. If None, all notifications of theType
76 96 will be posted.
77 97 """
78 assert(observerCallback != None)
98 assert(callback != None)
79 99 self.registeredTypes.add(theType)
80 100 self.registeredSenders.add(sender)
81 self.observers.setdefault((theType,sender), set()).add(observerCallback)
101 self.observers.setdefault((theType,sender), set()).add(callback)
102
103 def remove_all_observers(self):
104 """Removes all observers from this notification center"""
105
106 self._init_observers()
82 107
83 108
84 109
85 110 sharedCenter = NotificationCenter() No newline at end of file
@@ -1,118 +1,179 b''
1 1 # encoding: utf-8
2 2
3 3 """This file contains unittests for the notification.py module."""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 from IPython.kernel.core.notification import NotificationCenter,\
19 sharedCenter
18 import unittest
19 import IPython.kernel.core.notification as notification
20 from nose.tools import timed
20 21
21 22 #
22 23 # Supporting test classes
23 24 #
24 25
25 26 class Observer(object):
26 27 """docstring for Observer"""
27 def __init__(self, expectedType, expectedSender, **kwargs):
28 def __init__(self, expectedType, expectedSender,
29 center=notification.sharedCenter, **kwargs):
28 30 super(Observer, self).__init__()
29 31 self.expectedType = expectedType
30 32 self.expectedSender = expectedSender
31 33 self.expectedKwArgs = kwargs
32 34 self.recieved = False
33 sharedCenter.add_observer(self.callback,
34 self.expectedType,
35 self.expectedSender)
35 center.add_observer(self.callback,
36 self.expectedType,
37 self.expectedSender)
36 38
37 39
38 40 def callback(self, theType, sender, args={}):
39 41 """callback"""
40 42
41 assert(theType == self.expectedType)
42 assert(sender == self.expectedSender)
43 assert(theType == self.expectedType or
44 self.expectedType == None)
45 assert(sender == self.expectedSender or
46 self.expectedSender == None)
43 47 assert(args == self.expectedKwArgs)
44 48 self.recieved = True
45 49
46 50
47 51 def verify(self):
48 52 """verify"""
49 53
50 54 assert(self.recieved)
51 55
56 def reset(self):
57 """reset"""
58
59 self.recieved = False
60
52 61
53 62
54 63 class Notifier(object):
55 64 """docstring for Notifier"""
56 65 def __init__(self, theType, **kwargs):
57 66 super(Notifier, self).__init__()
58 67 self.theType = theType
59 68 self.kwargs = kwargs
60 69
61 def post(self, center=sharedCenter):
70 def post(self, center=notification.sharedCenter):
62 71 """fire"""
63 72
64 73 center.post_notification(self.theType, self,
65 74 **self.kwargs)
66 75
67 76
68 77 #
69 78 # Test Cases
70 79 #
71 80
72
73 def test_notification_delivered():
74 """Test that notifications are delivered"""
75 expectedType = 'EXPECTED_TYPE'
76 sender = Notifier(expectedType)
77 observer = Observer(expectedType, sender)
81 class NotificationTests(unittest.TestCase):
82 """docstring for NotificationTests"""
78 83
79 sender.post()
84 def tearDown(self):
85 notification.sharedCenter.remove_all_observers()
80 86
81 observer.verify()
82
83
84 def test_type_specificity():
85 """Test that observers are registered by type"""
87 def test_notification_delivered(self):
88 """Test that notifications are delivered"""
89 expectedType = 'EXPECTED_TYPE'
90 sender = Notifier(expectedType)
91 observer = Observer(expectedType, sender)
92
93 sender.post()
94
95 observer.verify()
86 96
87 expectedType = 1
88 unexpectedType = "UNEXPECTED_TYPE"
89 sender = Notifier(expectedType)
90 unexpectedSender = Notifier(unexpectedType)
91 observer = Observer(expectedType, sender)
92 97
93 sender.post()
94 unexpectedSender.post()
98 def test_type_specificity(self):
99 """Test that observers are registered by type"""
100
101 expectedType = 1
102 unexpectedType = "UNEXPECTED_TYPE"
103 sender = Notifier(expectedType)
104 unexpectedSender = Notifier(unexpectedType)
105 observer = Observer(expectedType, sender)
95 106
96 observer.verify()
97
98
99 def test_sender_specificity():
100 """Test that observers are registered by sender"""
107 sender.post()
108 unexpectedSender.post()
101 109
102 expectedType = "EXPECTED_TYPE"
103 sender1 = Notifier(expectedType)
104 sender2 = Notifier(expectedType)
105 observer = Observer(expectedType, sender1)
110 observer.verify()
106 111
107 sender1.post()
108 sender2.post()
109 112
110 observer.verify()
111
112
113 def test_complexity_with_no_observers():
114 """Test that the notification center's algorithmic complexity is O(1)
115 with no registered observers (for the given notification type)
116 """
113 def test_sender_specificity(self):
114 """Test that observers are registered by sender"""
115
116 expectedType = "EXPECTED_TYPE"
117 sender1 = Notifier(expectedType)
118 sender2 = Notifier(expectedType)
119 observer = Observer(expectedType, sender1)
120
121 sender1.post()
122 sender2.post()
123
124 observer.verify()
125
126
127 def test_remove_all_observers(self):
128 """White-box test for remove_all_observers"""
129
130 for i in xrange(10):
131 Observer('TYPE', None, center=notification.sharedCenter)
132
133 self.assert_(len(notification.sharedCenter.observers[('TYPE',None)]) >= 10,
134 "observers registered")
135
136 notification.sharedCenter.remove_all_observers()
137
138 self.assert_(len(notification.sharedCenter.observers) == 0, "observers removed")
139
140
141 def test_any_sender(self):
142 """test_any_sender"""
143
144 expectedType = "EXPECTED_TYPE"
145 sender1 = Notifier(expectedType)
146 sender2 = Notifier(expectedType)
147 observer = Observer(expectedType, None)
148
149
150 sender1.post()
151 observer.verify()
152
153 observer.reset()
154 sender2.post()
155 observer.verify()
156
157
158 @timed(.01)
159 def test_post_performance(self):
160 """Test that post_notification, even with many registered irrelevant
161 observers is fast"""
162
163 for i in xrange(10):
164 Observer("UNRELATED_TYPE", None)
165
166 o = Observer('EXPECTED_TYPE', None)
167
168 notification.sharedCenter.post_notification('EXPECTED_TYPE', self)
169
170 o.verify()
171
172
173 def test_complexity_with_no_observers(self):
174 """Test that the notification center's algorithmic complexity is O(1)
175 with no registered observers (for the given notification type)
176 """
177
178 self.fail("I'm not sure how to test this.")
117 179
118 assert(False) #I'm not sure how to test this yet
General Comments 0
You need to be logged in to leave comments. Login now