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