1
2
3
4
5
6
7
8
9
10
11 """
12 The observable module provides an interface and an optional mixin class that
13 provide an Observer pattern for attribute based change notifications of an
14 object.
15
16 An object that is Observable (i.e. provides the IObservable interface) will
17 allow attribute observers, a.k.a. listeners, to be attached or detached for
18 specific attribute names. These observers will be notified whenever the
19 specified attribute changes value.
20
21 Observers can be any Python object that is callable.
22
23 An example of using the observer pattern in your implementation is:
24
25
26 class MyObject(MyParentClass, ObservableMixin):
27 def __init__(self):
28 super(MyObject, self).__init__()
29 self.name = "Super Duper Object"
30 self.age = 42
31
32 def doIt(self):
33 self.name = "I changed my name!"
34 self.age = 37
35
36 def ageListener(observable, attrName, oldValue, newValue):
37 print "Age has been changed from %d to %d" % (oldValue, newValue)
38
39 foo = MyObject()
40 foo.attachAttributeObserver("age", ageListener)
41 foo.doIt()
42
43
44 This implementation will likely only work with new style classes that have been
45 properly implemented.
46 """
47
48 import Globals
49 import zope.interface
50
52 """
53 Classes that implement the IObservable interface agree to provide the
54 Observer pattern for object attribute changes.
55 """
57 """
58 Attaches an observer that will be notified when the specified attribute
59 changes value.
60
61 @param name the attribute name to observer
62 @param observer the observer/listener to be notified
63 @type observer callable
64 """
65 pass
66
68 """
69 Removes an observer from watching the specified attribute.
70
71 @param name the attribute name to remove the observer from
72 @param observer the observer/listener to be removed
73 """
74 pass
75
77 """
78 Notify all registered observers that an attribute has changed value.
79 Register observers must be a Python callable and will receive the
80 following keyword arguments:
81 observable - a reference to the observed object
82 attrName - the attribute name that has changed
83 oldValue - the previous value
84 newValue - the new value
85
86 @param name the attribute name that has changed
87 @param oldValue the old attribute value
88 @param newValue the new attribute value
89 """
90 pass
91
93 """
94 A mixin class that provides an implementation of the IObservable interface
95 for any new-style class to use. This implementation will provide
96 notification for all attribute changes, except for the attributes used
97 to track the registered observers themselves.
98 """
99 zope.interface.implements(IObservable)
100
104
106 if not callable(observer):
107 raise ValueError("observer must be callable")
108
109 if not name in self._observers:
110 self._observers[name] = []
111
112 if observer not in self._observers[name]:
113 self._observers[name].append(observer)
114
116 try:
117 self._observers[name].remove(observer)
118 except (KeyError, ValueError):
119 pass
120
122
123
124 if hasattr(self, '_observers') and name in self._observers:
125 for observer in self._observers[name]:
126 observer(observable=self,
127 attrName=name,
128 oldValue=oldValue,
129 newValue=newValue)
130
137
140
141
143
144 reservedNames = ('_observers','_obj','_doSetattr','notifyAttributeChange', 'detachAttributeObserver',
145 'attachAttributeObserver')
146
150
156
162