##// END OF EJS Templates
fixed None for type/sender
Barry Wark -
Show More
@@ -1,85 +1,110 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """The IPython Core Notification Center.
3 """The IPython Core Notification Center.
4
4
5 See docs/blueprints/notification_blueprint.txt for an overview of the
5 See docs/blueprints/notification_blueprint.txt for an overview of the
6 notification module.
6 notification module.
7 """
7 """
8
8
9 __docformat__ = "restructuredtext en"
9 __docformat__ = "restructuredtext en"
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18
18
19 class NotificationCenter(object):
19 class NotificationCenter(object):
20 """Synchronous notification center"""
20 """Synchronous notification center"""
21 def __init__(self):
21 def __init__(self):
22 super(NotificationCenter, self).__init__()
22 super(NotificationCenter, self).__init__()
23 self._init_observers()
24
25
26 def _init_observers(self):
27 """Initialize observer storage"""
28
23 self.registeredTypes = set() #set of types that are observed
29 self.registeredTypes = set() #set of types that are observed
24 self.registeredSenders = set() #set of senders that are observed
30 self.registeredSenders = set() #set of senders that are observed
25 self.observers = {} #map (type,sender) => callback (callable)
31 self.observers = {} #map (type,sender) => callback (callable)
26
32
27
33
28 def post_notification(self, theType, sender, **kwargs):
34 def post_notification(self, theType, sender, **kwargs):
29 """Post notification (type,sender,**kwargs) to all registered
35 """Post notification (type,sender,**kwargs) to all registered
30 observers.
36 observers.
31
37
32 Implementation
38 Implementation
33 --------------
39 --------------
34 * If no registered observers, performance is O(1).
40 * If no registered observers, performance is O(1).
35 * Notificaiton order is undefined.
41 * Notificaiton order is undefined.
36 * Notifications are posted synchronously.
42 * Notifications are posted synchronously.
37 """
43 """
38
44
39 if(theType==None or sender==None):
45 if(theType==None or sender==None):
40 raise Exception("NotificationCenter.post_notification requires \
46 raise Exception("NotificationCenter.post_notification requires \
41 type and sender.")
47 type and sender.")
42
48
43 # If there are no registered observers for the type/sender pair
49 # If there are no registered observers for the type/sender pair
44 if((theType not in self.registeredTypes) or
50 if((theType not in self.registeredTypes and None not in self.registeredTypes) or
45 (sender not in self.registeredSenders)):
51 (sender not in self.registeredSenders and None not in self.registeredSenders)):
52 print theType,sender,self.registeredTypes,self.registeredSenders
46 return
53 return
47
54
48 keys = ((theType,sender), (None, sender), (theType, None), (None,None))
55 for o in self._observers_for_notification(theType, sender):
49 observers = set()
50 for k in keys:
51 observers.update(self.observers.get(k, set()))
52
53 for o in observers:
54 o(theType, sender, args=kwargs)
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 """Add an observer callback to this notification center.
78 """Add an observer callback to this notification center.
59
79
60 The given callback will be called upon posting of notifications of
80 The given callback will be called upon posting of notifications of
61 the given type/sender and will receive any additional kwargs passed
81 the given type/sender and will receive any additional kwargs passed
62 to post_notification.
82 to post_notification.
63
83
64 Parameters
84 Parameters
65 ----------
85 ----------
66 observerCallback : callable
86 observerCallback : callable
67 Callable. Must take at least two arguments::
87 Callable. Must take at least two arguments::
68 observerCallback(type, sender, args={})
88 observerCallback(type, sender, args={})
69
89
70 theType : hashable
90 theType : hashable
71 The notification type. If None, all notifications from sender
91 The notification type. If None, all notifications from sender
72 will be posted.
92 will be posted.
73
93
74 sender : hashable
94 sender : hashable
75 The notification sender. If None, all notifications of theType
95 The notification sender. If None, all notifications of theType
76 will be posted.
96 will be posted.
77 """
97 """
78 assert(observerCallback != None)
98 assert(callback != None)
79 self.registeredTypes.add(theType)
99 self.registeredTypes.add(theType)
80 self.registeredSenders.add(sender)
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 sharedCenter = NotificationCenter() No newline at end of file
110 sharedCenter = NotificationCenter()
@@ -1,118 +1,179 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """This file contains unittests for the notification.py module."""
3 """This file contains unittests for the notification.py module."""
4
4
5 __docformat__ = "restructuredtext en"
5 __docformat__ = "restructuredtext en"
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 from IPython.kernel.core.notification import NotificationCenter,\
18 import unittest
19 sharedCenter
19 import IPython.kernel.core.notification as notification
20 from nose.tools import timed
20
21
21 #
22 #
22 # Supporting test classes
23 # Supporting test classes
23 #
24 #
24
25
25 class Observer(object):
26 class Observer(object):
26 """docstring for Observer"""
27 """docstring for Observer"""
27 def __init__(self, expectedType, expectedSender, **kwargs):
28 def __init__(self, expectedType, expectedSender,
29 center=notification.sharedCenter, **kwargs):
28 super(Observer, self).__init__()
30 super(Observer, self).__init__()
29 self.expectedType = expectedType
31 self.expectedType = expectedType
30 self.expectedSender = expectedSender
32 self.expectedSender = expectedSender
31 self.expectedKwArgs = kwargs
33 self.expectedKwArgs = kwargs
32 self.recieved = False
34 self.recieved = False
33 sharedCenter.add_observer(self.callback,
35 center.add_observer(self.callback,
34 self.expectedType,
36 self.expectedType,
35 self.expectedSender)
37 self.expectedSender)
36
38
37
39
38 def callback(self, theType, sender, args={}):
40 def callback(self, theType, sender, args={}):
39 """callback"""
41 """callback"""
40
42
41 assert(theType == self.expectedType)
43 assert(theType == self.expectedType or
42 assert(sender == self.expectedSender)
44 self.expectedType == None)
45 assert(sender == self.expectedSender or
46 self.expectedSender == None)
43 assert(args == self.expectedKwArgs)
47 assert(args == self.expectedKwArgs)
44 self.recieved = True
48 self.recieved = True
45
49
46
50
47 def verify(self):
51 def verify(self):
48 """verify"""
52 """verify"""
49
53
50 assert(self.recieved)
54 assert(self.recieved)
51
55
56 def reset(self):
57 """reset"""
58
59 self.recieved = False
60
52
61
53
62
54 class Notifier(object):
63 class Notifier(object):
55 """docstring for Notifier"""
64 """docstring for Notifier"""
56 def __init__(self, theType, **kwargs):
65 def __init__(self, theType, **kwargs):
57 super(Notifier, self).__init__()
66 super(Notifier, self).__init__()
58 self.theType = theType
67 self.theType = theType
59 self.kwargs = kwargs
68 self.kwargs = kwargs
60
69
61 def post(self, center=sharedCenter):
70 def post(self, center=notification.sharedCenter):
62 """fire"""
71 """fire"""
63
72
64 center.post_notification(self.theType, self,
73 center.post_notification(self.theType, self,
65 **self.kwargs)
74 **self.kwargs)
66
75
67
76
68 #
77 #
69 # Test Cases
78 # Test Cases
70 #
79 #
71
80
72
81 class NotificationTests(unittest.TestCase):
73 def test_notification_delivered():
82 """docstring for NotificationTests"""
74 """Test that notifications are delivered"""
75 expectedType = 'EXPECTED_TYPE'
76 sender = Notifier(expectedType)
77 observer = Observer(expectedType, sender)
78
83
79 sender.post()
84 def tearDown(self):
85 notification.sharedCenter.remove_all_observers()
80
86
81 observer.verify()
87 def test_notification_delivered(self):
82
88 """Test that notifications are delivered"""
83
89 expectedType = 'EXPECTED_TYPE'
84 def test_type_specificity():
90 sender = Notifier(expectedType)
85 """Test that observers are registered by type"""
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()
98 def test_type_specificity(self):
94 unexpectedSender.post()
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()
107 sender.post()
97
108 unexpectedSender.post()
98
99 def test_sender_specificity():
100 """Test that observers are registered by sender"""
101
109
102 expectedType = "EXPECTED_TYPE"
110 observer.verify()
103 sender1 = Notifier(expectedType)
104 sender2 = Notifier(expectedType)
105 observer = Observer(expectedType, sender1)
106
111
107 sender1.post()
108 sender2.post()
109
112
110 observer.verify()
113 def test_sender_specificity(self):
111
114 """Test that observers are registered by sender"""
112
115
113 def test_complexity_with_no_observers():
116 expectedType = "EXPECTED_TYPE"
114 """Test that the notification center's algorithmic complexity is O(1)
117 sender1 = Notifier(expectedType)
115 with no registered observers (for the given notification type)
118 sender2 = Notifier(expectedType)
116 """
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