Changeset 176
- Timestamp:
- 06/17/02 22:22:55 (6 years ago)
- Files:
-
- trunk/RBFoundation/RBFoundation/WeakBind.py (modified) (3 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/AssociativeObserver.py (modified) (3 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/AttributedSubject.py (modified) (2 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/BidableSubject.py (modified) (1 diff)
- trunk/RBJabber/RBJabber/SubjectObserver/CategorySubject.py (modified) (1 diff)
- trunk/RBJabber/RBJabber/SubjectObserver/Observer.py (modified) (3 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/SchedulerSubject.py (modified) (1 diff)
- trunk/RBJabber/RBJabber/SubjectObserver/StateMachine.py (modified) (4 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/Subject.py (modified) (3 diffs)
- trunk/RBJabber/RBJabber/SubjectObserver/__init__.py (modified) (4 diffs)
- trunk/RBSkinning/RBSkinning/wxTools/wxEvtHandlerBidableCategorySubject.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/RBFoundation/RBFoundation/WeakBind.py
r175 r176 113 113 return self._DoCall(args, kw) 114 114 115 def __getattribute__(self, name): 116 try: 117 return BoundCallableBase.__getattribute__(self, name) 118 except AttributeError: 119 if self.im_self and self.im_self(): 120 try: 121 return getattr(self.im_self(), name) 122 except AttributeError: pass 123 if self.im_func and self.im_func(): 124 try: 125 return getattr(self.im_func(), name) 126 except AttributeError: pass 127 raise 128 115 129 def __eq__(self, other): 116 130 if isinstance(other, WeakBoundCallable): … … 164 178 return self._DoCall(args, kw) 165 179 180 def __getattribute__(self, name): 181 try: 182 return BoundCallableBase.__getattribute__(self, name) 183 except AttributeError: 184 if self.im_self and self.im_self(): 185 try: 186 return getattr(self.im_self(), name) 187 except AttributeError: pass 188 if self.im_func and self.im_func(): 189 try: 190 return getattr(self.im_func(), name) 191 except AttributeError: pass 192 raise 193 166 194 def __eq__(self, other): 167 195 if isinstance(other, StrongBoundCallable): … … 194 222 return callback 195 223 224 def StrongBindCallable(callback): 225 """Weakly binds a callable object only if needed.""" 226 if isinstance(callback, BoundCallableBase): 227 # It's already bound in some form or another, 228 # but we have to guard it from being wrapped 229 # again, because it is itself an instance. 230 return callback 231 elif isinstance(callback, typesRequireBinding): 232 # Well if it requires binding, then we should 233 # do so! 234 return StrongBoundCallable(callback) 235 else: 236 # not quite sure what it is, but it does not require binding 237 return callback 238 196 239 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 197 240 #~ Testing trunk/RBJabber/RBJabber/SubjectObserver/AssociativeObserver.py
r90 r176 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """Observer implementation that can delegate multiple input updates to multiple 34 receivers based on what the delegate observer is interested in. Note: This is less 35 effecient than Subject-side category based filtering, but does not depend upon the 36 subject implementing the category interface. 37 """ 38 33 39 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 40 #~ Imports … … 36 42 37 43 from Foundation.WeakBind import BindCallable 44 from Foundation.SubjectObserver import ProxyBidableCategorySubjectMixin 38 45 39 46 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 41 48 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 49 43 class AssociativeObserver :50 class AssociativeObserver(ProxyBidableCategorySubjectMixin): 44 51 def __init__(self): 45 52 self._associations = {} 46 53 47 def AddAssociation(self, association, observer):48 self._associations.setdefault( association, []).append(BindCallable(observer))54 def AddAssociation(self, category, observer): 55 self._associations.setdefault(category, []).append(BindCallable(observer)) 49 56 return self 50 57 51 def Bid(self, subject, **UpdateDict): 52 for key, value in UpdateDict.iteritems(): 53 for observer in self._associations.get(key, []): 54 subject._GetBid(observer, UpdateDict) 58 def _ObserverList(self, category): 59 return self._associations.get(category, []) 55 60 56 def Update(self, subject, **UpdateDict): 57 pass # Weird condition... no bids on it, but we really dont care here 61 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 62 #~ Testing 63 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 65 if __name__=='__main__': 66 print "Testing..." 67 import BidableSubject 68 s = BidableSubject.BidableSubject() 69 from Observer import Observer 70 71 def AssertSubject(subject, value): 72 assert subject is s 73 def AssertFalse(subject, value): 74 assert 0 75 76 ao = AssociativeObserver() 77 s.AddObserver(ao) 78 79 ao.AddAssociation('test', Observer(AssertFalse, 100)) 80 ao.AddAssociation('test', Observer(AssertFalse, -1)) 81 82 ao.AddAssociation('value', Observer(AssertFalse, 9)) 83 ao.AddAssociation('value', Observer(AssertSubject, 10)) 84 ao.AddAssociation('value', Observer(AssertSubject)) 85 ao.AddAssociation('value', AssertSubject) 86 87 ao.AddAssociation('value2', Observer(AssertSubject)) 88 ao.AddAssociation('value2', AssertSubject) 89 90 s.UpdateObservers(value=42) 91 92 print "Test complete." 93 trunk/RBJabber/RBJabber/SubjectObserver/AttributedSubject.py
r167 r176 30 30 ##~ 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 33 """Subject-based Foundation.AttributedDict 34 35 Similar to Foundation.AttributedDict, except that every modification causes an 36 UpdateObservers call.""" 32 37 33 38 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 159 164 160 165 class AttributedSubject(AttributedSubjectMixin, Subject): 166 """Couples AttributedSubjectMixin with a Subject propigation scheme.""" 161 167 def AddObserver(self, observer, call=0, **kw): 162 168 Subject.AddObserver(self, observer, **kw) trunk/RBJabber/RBJabber/SubjectObserver/BidableSubject.py
r164 r176 30 30 ##~ 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 33 """Adds bidding to the Subject/Observer mechanism so that 34 observers can "voluntarily" be out-bid to provide for 35 state-dependant event handling. 36 37 In order to bid, the observer must have a 'Bid' attribute 38 (value or callable), and the highest bidder wins, as defined 39 by the > operator.""" 32 40 33 41 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBJabber/RBJabber/SubjectObserver/CategorySubject.py
r170 r176 30 30 ##~ 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 33 """Adds 'categories' to subjects to allow for prefiltering of subject 34 notifications. Simply put, you have to add an observer for a specific 35 category, and that observer will only be called when that category is 36 updated.""" 32 37 33 38 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBJabber/RBJabber/SubjectObserver/Observer.py
r88 r176 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """Observer implementation. 34 35 Note: You only need an Observer instance if you need to place a bid value. 36 otherwise the callable object can be passed straight to the subject. 37 """ 38 33 39 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 40 #~ Imports … … 42 48 43 49 class Observer(BoundCallable): 50 """Note: Only needed if you are adding a Bid value to the observer; 51 otherwise the callable object can be passed straight to the subject.""" 52 44 53 def __init__(self, callback=None, Bid=None): 45 54 super(Observer, self).__init__(callback or self.Update) … … 56 65 def Update(self, subject, **UpdateDict): 57 66 print "On Update:", subject.__class__.__name__, UpdateDict 67 68 69 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 70 #~ Testing 71 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 72 73 if __name__=='__main__': 74 print "Testing..." 75 import BidableSubject 76 s = BidableSubject.BidableSubject() 77 78 def AssertSubject(subject, value): 79 assert subject is s 80 def AssertFalse(subject, value): 81 assert 0 82 83 s.AddObserver(Observer(AssertSubject, 10)) 84 s.AddObserver(Observer(AssertFalse, 9)) 85 s.AddObserver(Observer(AssertFalse, 8)) 86 s.AddObserver(Observer(AssertFalse, -1)) 87 # The following two will get called because of no bid value 88 s.AddObserver(Observer(AssertSubject)) 89 s.AddObserver(AssertSubject) 90 91 s.UpdateObservers(value=42) 92 print "Test complete." 93 trunk/RBJabber/RBJabber/SubjectObserver/SchedulerSubject.py
r170 r176 30 30 ##~ 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 33 """Subject/Observer like implementation of sched""" 32 34 33 35 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBJabber/RBJabber/SubjectObserver/StateMachine.py
r164 r176 30 30 ##~ 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 33 """State machine implementation using the Subject/Observer design pattern. 34 35 By defining each state as a subject, the state can "call you back" in order to 36 compute complext firing semantics, or when the state is reached. 37 """ 32 38 33 39 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 68 74 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 69 75 70 class State (CategorySubject):76 class StateSubject(CategorySubject): 71 77 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 72 78 #~ Constants / Variables / Etc. … … 92 98 #~ Public Methods 93 99 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 94 95 def AddObserver(self, callable, category='', **kw):96 category = category or 'precondition'97 return CategorySubject.AddObserver(self, category, callable, **kw)98 100 99 101 def SetState(self, value =1): … … 125 127 def AddOutflux(self, Outflux): 126 128 Outflux.AddInflux(self) 129 130 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 131 132 class State(StateSubject): 133 def AddObserver(self, callable, category='', **kw): 134 category = category or 'precondition' 135 return CategorySubject.AddObserver(self, category, callable, **kw) 127 136 128 137 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBJabber/RBJabber/SubjectObserver/Subject.py
r170 r176 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """Maintains a list of montioring observers that get updated when 34 UpdateObservers or UpdateObserversEx get called, unless the subject is Locked. 35 A lock can be obtained by calling Lock, and it maintained until the lock object 36 no longer exisits or is explicitly released. 37 38 WeakBind module is used extensively to prevent reference chains keeping objects in 39 memory unnecessarily.""" 40 33 41 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 42 #~ Imports … … 43 51 44 52 class Subject(object): 45 """Maintains a list of montioring observers that get updated when46 UpdateObservers or UpdateObserversEx get called, unless the subject is Locked.47 A lock can be obtained by calling Lock, and it maintained until the lock object48 no longer exisits or is explicitly released."""49 50 53 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 54 #~ Special … … 76 79 77 80 def ClearObservers(self): 81 """Removes all observers from the internal collection""" 78 82 self._observers[:] = [] 79 83 return self trunk/RBJabber/RBJabber/SubjectObserver/__init__.py
r159 r176 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """TODO: Document""" 33 """Subject/Observer with bells on. 34 35 The goal of this package is to make both observers and subjects very simple to create 36 maintain, while retaining both flexable and powerful subjects / observers. The simplest 37 observers are just callable objects, and the simplest subjects keep a list of observers 38 to notify. More advanced classes include bidable, attributed, and categorized 39 subject/observers. 40 41 This main module collects and blends many of the subject and observer types to create 42 extremely useful subjects and observers. 43 """ 34 44 35 45 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 38 48 39 49 import Observer as _Observer 40 import AssociativeObserver as _AssociativeObserver41 42 50 import Subject as _Subject 43 51 import CategorySubject as _CategorySubject … … 66 74 67 75 class ProxyBidableCategorySubjectMixin(object): 76 """Allows some subject to proxy for a different subject as an observer of that subject, 77 while maintaining bid-sequences and categories""" 78 68 79 def __call__(self, subject, **UpdateDict): 69 80 pass … … 80 91 81 92 class ProxyBidableSubjectMixin(object): 93 """Allows some subject to proxy for a different subject as an observer of that subject, 94 while maintaining bid-sequences""" 95 82 96 def __call__(self, subject, **UpdateDict): 83 97 pass trunk/RBSkinning/RBSkinning/wxTools/wxEvtHandlerBidableCategorySubject.py
r164 r176 31 31 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 32 33 """Subject/Observer wrapping of wxEvents, allowing 0 to n recipients for any given event. 34 35 Avoids having to deal with evt.Skip, or PushEventHandler for every needed layer by building 36 upon Bidable and Category subjects from Foundation.SubjectObserver. 37 38 To use: 39 EvtSubject = wxEvtSubject() 40 EvtSubject.PushEventHandler(window_or_evthandler) 41 EvtSubject.AddObserver(wxEVT_SIZE, callback_one) 42 EvtSubject.AddObserver(wxEVT_SIZE, callback_n) 43 """ 44 33 45 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 46 #~ Imports … … 44 56 45 57 class wxEvtHandlerBidableCategorySubject(BidableCategorySubject): 46 def __init__(self): 58 EventCallbackName = 'event' 59 60 def __init__(self, wxEvtHandlerBidableCategorySubject=None): 47 61 self.EvtHandler = wx.wxEvtHandler() 48 62 BidableCategorySubject.__init__(self) 63 if EventHandler: self.PushEventHandler(EventHandler) 49 64 50 65 def _OnEvent(self, evt): 51 if not self.UpdateObserversEx({( 'event', evt.GetEventType()):evt}):66 if not self.UpdateObserversEx({(self.EventCallbackName, evt.GetEventType()):evt}): 52 67 evt.Skip() 53 68 69 def PushEventHandler(self, EventHandler): 70 self.EvtHandler.SetNextHandler(EventHandler) 71 EventHandler.SetPreviousHandler(self.EvtHandler) 72 54 73 def AddObserver(self, category, *args, **kw): 55 74 self.EvtHandler.Connect(-1, -1, category, BindCallable(self._OnEvent)) 56 BidableCategorySubject.AddObserver(self, ( 'event', category), *args, **kw)75 BidableCategorySubject.AddObserver(self, (self.EventCallbackName, category), *args, **kw) 57 76 77 wxEvtSubject = wxEvtHandlerBidableCategorySubject
