PyDispatcher-2.0.5/0000755000175000001440000000000012455637705015077 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/pydispatch/0000755000175000001440000000000012455637705017247 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/pydispatch/dispatcher.py0000644000175000001440000004055212451340306021735 0ustar mcfletchusers00000000000000"""Multiple-producer-multiple-consumer signal-dispatching dispatcher is the core of the PyDispatcher system, providing the primary API and the core logic for the system. Module attributes of note: Any -- Singleton used to signal either "Any Sender" or "Any Signal". See documentation of the _Any class. Anonymous -- Singleton used to signal "Anonymous Sender" See documentation of the _Anonymous class. Internal attributes: WEAKREF_TYPES -- tuple of types/classes which represent weak references to receivers, and thus must be de- referenced on retrieval to retrieve the callable object connections -- { senderkey (id) : { signal : [receivers...]}} senders -- { senderkey (id) : weakref(sender) } used for cleaning up sender references on sender deletion sendersBack -- { receiverkey (id) : [senderkey (id)...] } used for cleaning up receiver references on receiver deletion, (considerably speeds up the cleanup process vs. the original code.) """ import weakref from pydispatch import saferef, robustapply, errors class _Parameter: """Used to represent default parameter values.""" def __repr__(self): return self.__class__.__name__ class _Any(_Parameter): """Singleton used to signal either "Any Sender" or "Any Signal" The Any object can be used with connect, disconnect, send, or sendExact to signal that the parameter given Any should react to all senders/signals, not just a particular sender/signal. """ Any = _Any() class _Anonymous(_Parameter): """Singleton used to signal "Anonymous Sender" The Anonymous object is used to signal that the sender of a message is not specified (as distinct from being "any sender"). Registering callbacks for Anonymous will only receive messages sent without senders. Sending with anonymous will only send messages to those receivers registered for Any or Anonymous. Note: The default sender for connect is Any, while the default sender for send is Anonymous. This has the effect that if you do not specify any senders in either function then all messages are routed as though there was a single sender (Anonymous) being used everywhere. """ Anonymous = _Anonymous() WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) connections = {} senders = {} sendersBack = {} def connect(receiver, signal=Any, sender=Any, weak=True): """Connect receiver to sender for signal receiver -- a callable Python object which is to receive messages/signals/events. Receivers must be hashable objects. if weak is True, then receiver must be weak-referencable (more precisely saferef.safeRef() must be able to create a reference to the receiver). Receivers are fairly flexible in their specification, as the machinery in the robustApply module takes care of most of the details regarding figuring out appropriate subsets of the sent arguments to apply to a given receiver. Note: if receiver is itself a weak reference (a callable), it will be de-referenced by the system's machinery, so *generally* weak references are not suitable as receivers, though some use might be found for the facility whereby a higher-level library passes in pre-weakrefed receiver references. signal -- the signal to which the receiver should respond if Any, receiver will receive any signal from the indicated sender (which might also be Any, but is not necessarily Any). Otherwise must be a hashable Python object other than None (DispatcherError raised on None). sender -- the sender to which the receiver should respond if Any, receiver will receive the indicated signals from any sender. if Anonymous, receiver will only receive indicated signals from send/sendExact which do not specify a sender, or specify Anonymous explicitly as the sender. Otherwise can be any python object. weak -- whether to use weak references to the receiver By default, the module will attempt to use weak references to the receiver objects. If this parameter is false, then strong references will be used. returns None, may raise DispatcherTypeError """ if signal is None: raise errors.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) ) if weak: receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) senderkey = id(sender) if senderkey in connections: signals = connections[senderkey] else: connections[senderkey] = signals = {} # Keep track of senders for cleanup. # Is Anonymous something we want to clean up? if sender not in (None, Anonymous, Any): def remove(object, senderkey=senderkey): _removeSender(senderkey=senderkey) # Skip objects that can not be weakly referenced, which means # they won't be automatically cleaned up, but that's too bad. try: weakSender = weakref.ref(sender, remove) senders[senderkey] = weakSender except: pass receiverID = id(receiver) # get current set, remove any current references to # this receiver in the set, including back-references if signal in signals: receivers = signals[signal] _removeOldBackRefs(senderkey, signal, receiver, receivers) else: receivers = signals[signal] = [] try: current = sendersBack.get( receiverID ) if current is None: sendersBack[ receiverID ] = current = [] if senderkey not in current: current.append(senderkey) except: pass receivers.append(receiver) def disconnect(receiver, signal=Any, sender=Any, weak=True): """Disconnect receiver from sender for signal receiver -- the registered receiver to disconnect signal -- the registered signal to disconnect sender -- the registered sender to disconnect weak -- the weakref state to disconnect disconnect reverses the process of connect, the semantics for the individual elements are logically equivalent to a tuple of (receiver, signal, sender, weak) used as a key to be deleted from the internal routing tables. (The actual process is slightly more complex but the semantics are basically the same). Note: Using disconnect is not required to cleanup routing when an object is deleted, the framework will remove routes for deleted objects automatically. It's only necessary to disconnect if you want to stop routing to a live object. returns None, may raise DispatcherTypeError or DispatcherKeyError """ if signal is None: raise errors.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) ) if weak: receiver = saferef.safeRef(receiver) senderkey = id(sender) try: signals = connections[senderkey] receivers = signals[signal] except KeyError: raise errors.DispatcherKeyError( """No receivers found for signal %r from sender %r""" %( signal, sender ) ) try: # also removes from receivers _removeOldBackRefs(senderkey, signal, receiver, receivers) except ValueError: raise errors.DispatcherKeyError( """No connection to receiver %s for signal %s from sender %s""" %( receiver, signal, sender ) ) _cleanupConnections(senderkey, signal) def getReceivers( sender = Any, signal = Any ): """Get list of receivers from global tables This utility function allows you to retrieve the raw list of receivers from the connections table for the given sender and signal pair. Note: there is no guarantee that this is the actual list stored in the connections table, so the value should be treated as a simple iterable/truth value rather than, for instance a list to which you might append new records. Normally you would use liveReceivers( getReceivers( ...)) to retrieve the actual receiver objects as an iterable object. """ try: return connections[id(sender)][signal] except KeyError: return [] def liveReceivers(receivers): """Filter sequence of receivers to get resolved, live receivers This is a generator which will iterate over the passed sequence, checking for weak references and resolving them, then returning all live receivers. """ for receiver in receivers: if isinstance( receiver, WEAKREF_TYPES): # Dereference the weak reference. receiver = receiver() if receiver is not None: yield receiver else: yield receiver def getAllReceivers( sender = Any, signal = Any ): """Get list of all receivers from global tables This gets all receivers which should receive the given signal from sender, each receiver should be produced only once by the resulting generator """ receivers = {} for set in ( # Get receivers that receive *this* signal from *this* sender. getReceivers( sender, signal ), # Add receivers that receive *any* signal from *this* sender. getReceivers( sender, Any ), # Add receivers that receive *this* signal from *any* sender. getReceivers( Any, signal ), # Add receivers that receive *any* signal from *any* sender. getReceivers( Any, Any ), ): for receiver in set: if receiver: # filter out dead instance-method weakrefs try: if receiver not in receivers: receivers[receiver] = 1 yield receiver except TypeError: # dead weakrefs raise TypeError on hash... pass def send(signal=Any, sender=Anonymous, *arguments, **named): """Send signal from sender to all connected receivers. signal -- (hashable) signal value, see connect for details sender -- the sender of the signal if Any, only receivers registered for Any will receive the message. if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message Otherwise can be any python object (normally one registered with a connect if you actually want something to occur). arguments -- positional arguments which will be passed to *all* receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care. named -- named arguments which will be filtered according to the parameters of the receivers to only provide those acceptable to the receiver. Return a list of tuple pairs [(receiver, response), ... ] if any receiver raises an error, the error propagates back through send, terminating the dispatch loop, so it is quite possible to not have all receivers called if a raises an error. """ # Call each receiver with whatever arguments it can accept. # Return a list of tuple pairs [(receiver, response), ... ]. responses = [] for receiver in liveReceivers(getAllReceivers(sender, signal)): response = robustapply.robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) responses.append((receiver, response)) return responses def sendExact( signal=Any, sender=Anonymous, *arguments, **named ): """Send signal only to those receivers registered for exact message sendExact allows for avoiding Any/Anonymous registered handlers, sending only to those receivers explicitly registered for a particular signal on a particular sender. """ responses = [] for receiver in liveReceivers(getReceivers(sender, signal)): response = robustapply.robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) responses.append((receiver, response)) return responses def _removeReceiver(receiver): """Remove receiver from connections.""" if not sendersBack: # During module cleanup the mapping will be replaced with None return False backKey = id(receiver) try: backSet = sendersBack.pop(backKey) except KeyError: return False else: for senderkey in backSet: try: signals = list(connections[senderkey].keys()) except KeyError: pass else: for signal in signals: try: receivers = connections[senderkey][signal] except KeyError: pass else: try: receivers.remove( receiver ) except Exception: pass _cleanupConnections(senderkey, signal) def _cleanupConnections(senderkey, signal): """Delete any empty signals for senderkey. Delete senderkey if empty.""" try: receivers = connections[senderkey][signal] except: pass else: if not receivers: # No more connected receivers. Therefore, remove the signal. try: signals = connections[senderkey] except KeyError: pass else: del signals[signal] if not signals: # No more signal connections. Therefore, remove the sender. _removeSender(senderkey) def _removeSender(senderkey): """Remove senderkey from connections.""" _removeBackrefs(senderkey) try: del connections[senderkey] except KeyError: pass # Senderkey will only be in senders dictionary if sender # could be weakly referenced. try: del senders[senderkey] except: pass def _removeBackrefs( senderkey): """Remove all back-references to this senderkey""" try: signals = connections[senderkey] except KeyError: signals = None else: items = signals.items() def allReceivers( ): for signal,set in items: for item in set: yield item for receiver in allReceivers(): _killBackref( receiver, senderkey ) def _removeOldBackRefs(senderkey, signal, receiver, receivers): """Kill old sendersBack references from receiver This guards against multiple registration of the same receiver for a given signal and sender leaking memory as old back reference records build up. Also removes old receiver instance from receivers """ try: index = receivers.index(receiver) # need to scan back references here and remove senderkey except ValueError: return False else: oldReceiver = receivers[index] del receivers[index] found = 0 signals = connections.get(signal) if signals is not None: for sig,recs in connections.get(signal,{}).items(): if sig != signal: for rec in recs: if rec is oldReceiver: found = 1 break if not found: _killBackref( oldReceiver, senderkey ) return True return False def _killBackref( receiver, senderkey ): """Do the actual removal of back reference from receiver to senderkey""" receiverkey = id(receiver) set = sendersBack.get( receiverkey, () ) while senderkey in set: try: set.remove( senderkey ) except: break if not set: try: del sendersBack[ receiverkey ] except KeyError: pass return True PyDispatcher-2.0.5/pydispatch/robustapply.py0000644000175000001440000000404512451340306022170 0ustar mcfletchusers00000000000000"""Robust apply mechanism Provides a function "call", which can sort out what arguments a given callable object can take, and subset the given arguments to match only those which are acceptable. """ import sys if sys.hexversion >= 0x3000000: im_func = '__func__' im_self = '__self__' im_code = '__code__' func_code = '__code__' else: im_func = 'im_func' im_self = 'im_self' im_code = 'im_code' func_code = 'func_code' def function( receiver ): """Get function-like callable object for given receiver returns (function_or_method, codeObject, fromMethod) If fromMethod is true, then the callable already has its first argument bound """ if hasattr(receiver, '__call__'): # Reassign receiver to the actual method that will be called. if hasattr( receiver.__call__, im_func) or hasattr( receiver.__call__, im_code): receiver = receiver.__call__ if hasattr( receiver, im_func ): # an instance-method... return receiver, getattr(getattr(receiver, im_func), func_code), 1 elif not hasattr( receiver, func_code): raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) return receiver, getattr(receiver,func_code), 0 def robustApply(receiver, *arguments, **named): """Call receiver with arguments and an appropriate subset of named """ receiver, codeObject, startIndex = function( receiver ) acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: if name in named: raise TypeError( """Argument %r specified both positionally and as a keyword for calling %r"""% ( name, receiver, ) ) if not (codeObject.co_flags & 8): # fc does not have a **kwds type parameter, therefore # remove unacceptable arguments. named = dict([(k,v) for k,v in named.items() if k in acceptable]) return receiver(*arguments, **named) PyDispatcher-2.0.5/pydispatch/__init__.py0000644000175000001440000000025212455637262021355 0ustar mcfletchusers00000000000000"""Multi-consumer multi-producer dispatching mechanism """ __version__ = "2.0.5" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" PyDispatcher-2.0.5/pydispatch/robust.py0000644000175000001440000000404312451340306021120 0ustar mcfletchusers00000000000000"""Module implementing error-catching version of send (sendRobust)""" from pydispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers from pydispatch.robustapply import robustApply def sendRobust( signal=Any, sender=Anonymous, *arguments, **named ): """Send signal from sender to all connected receivers catching errors signal -- (hashable) signal value, see connect for details sender -- the sender of the signal if Any, only receivers registered for Any will receive the message. if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message Otherwise can be any python object (normally one registered with a connect if you actually want something to occur). arguments -- positional arguments which will be passed to *all* receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care. named -- named arguments which will be filtered according to the parameters of the receivers to only provide those acceptable to the receiver. Return a list of tuple pairs [(receiver, response), ... ] if any receiver raises an error (specifically any subclass of Exception), the error instance is returned as the result for that receiver. """ # Call each receiver with whatever arguments it can accept. # Return a list of tuple pairs [(receiver, response), ... ]. responses = [] for receiver in liveReceivers(getAllReceivers(sender, signal)): try: response = robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) except Exception as err: responses.append((receiver, err)) else: responses.append((receiver, response)) return responsesPyDispatcher-2.0.5/pydispatch/saferef.py0000644000175000001440000001631612451340306021223 0ustar mcfletchusers00000000000000"""Refactored "safe reference" from dispatcher.py""" import weakref, traceback, sys if sys.hexversion >= 0x3000000: im_func = '__func__' im_self = '__self__' else: im_func = 'im_func' im_self = 'im_self' def safeRef(target, onDelete = None): """Return a *safe* weak reference to a callable target target -- the object to be weakly referenced, if it's a bound method reference, will create a BoundMethodWeakref, otherwise creates a simple weakref. onDelete -- if provided, will have a hard reference stored to the callable to be called after the safe reference goes out of scope with the reference object, (either a weakref or a BoundMethodWeakref) as argument. """ if hasattr(target, im_self): if getattr(target, im_self) is not None: # Turn a bound method into a BoundMethodWeakref instance. # Keep track of these instances for lookup by disconnect(). assert hasattr(target, im_func), """safeRef target %r has %s, but no %s, don't know how to create reference"""%( target,im_self,im_func) reference = BoundMethodWeakref( target=target, onDelete=onDelete ) return reference if onDelete is not None: return weakref.ref(target, onDelete) else: return weakref.ref( target ) class BoundMethodWeakref(object): """'Safe' and reusable weak references to instance methods BoundMethodWeakref objects provide a mechanism for referencing a bound method without requiring that the method object itself (which is normally a transient object) is kept alive. Instead, the BoundMethodWeakref object keeps weak references to both the object and the function which together define the instance method. Attributes: key -- the identity key for the reference, calculated by the class's calculateKey method applied to the target instance method deletionMethods -- sequence of callable objects taking single argument, a reference to this object which will be called when *either* the target object or target function is garbage collected (i.e. when this object becomes invalid). These are specified as the onDelete parameters of safeRef calls. weakSelf -- weak reference to the target object weakFunc -- weak reference to the target function Class Attributes: _allInstances -- class attribute pointing to all live BoundMethodWeakref objects indexed by the class's calculateKey(target) method applied to the target objects. This weak value dictionary is used to short-circuit creation so that multiple references to the same (object, function) pair produce the same BoundMethodWeakref instance. """ _allInstances = weakref.WeakValueDictionary() def __new__( cls, target, onDelete=None, *arguments,**named ): """Create new instance or return current instance Basically this method of construction allows us to short-circuit creation of references to already- referenced instance methods. The key corresponding to the target is calculated, and if there is already an existing reference, that is returned, with its deletionMethods attribute updated. Otherwise the new instance is created and registered in the table of already-referenced methods. """ key = cls.calculateKey(target) current =cls._allInstances.get(key) if current is not None: current.deletionMethods.append( onDelete) return current else: base = super( BoundMethodWeakref, cls).__new__( cls ) cls._allInstances[key] = base base.__init__( target, onDelete, *arguments,**named) return base def __init__(self, target, onDelete=None): """Return a weak-reference-like instance for a bound method target -- the instance-method target for the weak reference, must have and attributes and be reconstructable via: target..__get__( target. ) which is true of built-in instance methods. onDelete -- optional callback which will be called when this weak reference ceases to be valid (i.e. either the object or the function is garbage collected). Should take a single argument, which will be passed a pointer to this object. """ def remove(weak, self=self): """Set self.isDead to true when method or instance is destroyed""" methods = self.deletionMethods[:] del self.deletionMethods[:] try: del self.__class__._allInstances[ self.key ] except KeyError: pass for function in methods: try: if hasattr(function, '__call__' ): function( self ) except Exception as e: try: traceback.print_exc() except AttributeError: print('''Exception during saferef %s cleanup function %s: %s'''%( self, function, e )) self.deletionMethods = [onDelete] self.key = self.calculateKey( target ) self.weakSelf = weakref.ref(getattr(target,im_self), remove) self.weakFunc = weakref.ref(getattr(target,im_func), remove) self.selfName = getattr(target,im_self).__class__.__name__ self.funcName = str(getattr(target,im_func).__name__) def calculateKey( cls, target ): """Calculate the reference key for this reference Currently this is a two-tuple of the id()'s of the target object and the target function respectively. """ return (id(getattr(target,im_self)),id(getattr(target,im_func))) calculateKey = classmethod( calculateKey ) def __str__(self): """Give a friendly representation of the object""" return """%s( %s.%s )"""%( self.__class__.__name__, self.selfName, self.funcName, ) __repr__ = __str__ def __nonzero__( self ): """Whether we are still a valid reference""" return self() is not None __bool__ = __nonzero__ def __cmp__( self, other ): """Compare with another reference""" if not isinstance (other,self.__class__): return cmp( self.__class__, type(other) ) return cmp( self.key, other.key) def __call__(self): """Return a strong reference to the bound method If the target cannot be retrieved, then will return None, otherwise returns a bound instance method for our object and function. Note: You may call this method any number of times, as it does not invalidate the reference. """ target = self.weakSelf() if target is not None: function = self.weakFunc() if function is not None: return function.__get__(target) return None PyDispatcher-2.0.5/pydispatch/errors.py0000644000175000001440000000056312451340306021121 0ustar mcfletchusers00000000000000"""Error types for dispatcher mechanism """ class DispatcherError(Exception): """Base class for all Dispatcher errors""" class DispatcherKeyError(KeyError, DispatcherError): """Error raised when unknown (sender,signal) set specified""" class DispatcherTypeError(TypeError, DispatcherError): """Error raised when inappropriate signal-type specified (None)""" PyDispatcher-2.0.5/license.txt0000644000175000001440000000303412451340306017242 0ustar mcfletchusers00000000000000PyDispatcher License Copyright (c) 2001-2006, Patrick K. O'Brien and Contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The name of Patrick K. O'Brien, or the name of any Contributor, may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PyDispatcher-2.0.5/setup.cfg0000644000175000001440000000007312455637705016720 0ustar mcfletchusers00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 PyDispatcher-2.0.5/tests/0000755000175000001440000000000012455637705016241 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/tests/__init__.py0000644000175000001440000000005312451340306020330 0ustar mcfletchusers00000000000000"""Unit-tests for the dispatch project """ PyDispatcher-2.0.5/tests/test_saferef.py0000644000175000001440000000423712451340306021253 0ustar mcfletchusers00000000000000from pydispatch.saferef import * import unittest class T1( object): def x( self ): pass def t2(obj): pass class T2( object ): def __call__( self, obj ): pass class Tester (unittest.TestCase): def setUp (self): ts = [] ss = [] for x in range( 5000 ): t = T1() ts.append( t) s = safeRef(t.x, self._closure ) ss.append( s) ts.append( t2 ) ss.append( safeRef(t2, self._closure) ) for x in range( 30 ): t = T2() ts.append( t) s = safeRef(t, self._closure ) ss.append( s) self.ts = ts self.ss = ss self.closureCount = 0 def tearDown( self ): del self.ts del self.ss def testIn(self): """Test the "in" operator for safe references (cmp)""" for t in self.ts[:50]: assert safeRef(t.x) in self.ss def testValid(self): """Test that the references are valid (return instance methods)""" for s in self.ss: assert s() def testShortCircuit (self): """Test that creation short-circuits to reuse existing references""" sd = {} for s in self.ss: sd[s] = 1 for t in self.ts: if hasattr( t, 'x'): assert safeRef(t.x) in sd else: assert safeRef(t) in sd def testRepresentation (self): """Test that the reference object's representation works XXX Doesn't currently check the results, just that no error is raised """ repr( self.ss[-1] ) def test(self): self.closureCount = 0 wholeI = len(self.ts) for i in range( len(self.ts)-1, -1, -1): del self.ts[i] if wholeI-i != self.closureCount: """Unexpected number of items closed, expected %s, got %s closed"""%( wholeI-i,self.closureCount) def _closure(self, ref): """Dumb utility mechanism to increment deletion counter""" self.closureCount +=1 def getSuite(): return unittest.makeSuite(Tester,'test') if __name__ == "__main__": unittest.main ()PyDispatcher-2.0.5/tests/test_dispatcher.py0000644000175000001440000001216412451340306021764 0ustar mcfletchusers00000000000000from pydispatch.dispatcher import * from pydispatch import dispatcher, robust import unittest def x(a): return a class Dummy( object ): pass class Callable(object): def __call__( self, a ): return a def a( self, a ): return a class DispatcherTests(unittest.TestCase): """Test suite for dispatcher (barely started)""" def _isclean( self ): """Assert that everything has been cleaned up automatically""" assert len(dispatcher.sendersBack) == 0, dispatcher.sendersBack assert len(dispatcher.connections) == 0, dispatcher.connections assert len(dispatcher.senders) == 0, dispatcher.senders def testExact (self): a = Dummy() signal = 'this' connect( x, signal, a ) expected = [(x,a)] result = send('this',a, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal, a ) assert len(list(getAllReceivers(a,signal))) == 0 self._isclean() def testAnonymousSend(self): a = Dummy() signal = 'this' connect( x, signal ) expected = [(x,a)] result = send(signal,None, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal ) assert len(list(getAllReceivers(None,signal))) == 0 self._isclean() def testAnyRegistration(self): a = Dummy() signal = 'this' connect( x, signal, Any ) expected = [(x,a)] result = send('this',object(), a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal, Any ) expected = [] result = send('this',object(), a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(Any,signal))) == 0 self._isclean() def testAnyRegistration2(self): a = Dummy() signal = 'this' connect( x, Any, a ) expected = [(x,a)] result = send(signal,a, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, Any, a ) assert len(list(getAllReceivers(a,Any))) == 0 self._isclean() def testGarbageCollected(self): a = Callable() b = Dummy() signal = 'this' connect( a.a, signal, b ) expected = [] del a result = send('this',b, a=b) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(b,signal))) == 0, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) self._isclean() def testGarbageCollectedObj(self): class x: def __call__( self, a ): return a a = Callable() b = Dummy() signal = 'this' connect( a, signal, b ) expected = [] del a result = send('this',b, a=b) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(b,signal))) == 0, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) self._isclean() def testMultipleRegistration(self): a = Callable() b = Dummy() signal = 'this' connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) result = send('this',b, a=b) assert len( result ) == 1, result assert len(list(getAllReceivers(b,signal))) == 1, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) del a del b del result self._isclean() def testRobust( self ): """Test the sendRobust function""" signal = 'this' def fails( ): raise ValueError( signal ) a = object() connect( fails, Any, a ) result = robust.sendRobust(signal,a, a=a) err = result[0][1] assert isinstance( err, ValueError ) assert err.args == (signal,) def testParameterRepr(self): assert repr(dispatcher.Any) == '_Any', repr(dispatcher.Any) assert str(dispatcher.Any) == '_Any', str(dispatcher.Any) def testNoNoneSignal(self): self.assertRaises( errors.DispatcherTypeError, dispatcher.connect, x, signal=None ) self.assertRaises( errors.DispatcherTypeError, dispatcher.disconnect, x, signal=None ) def testDisconnectUnconnected(self): self.assertRaises( errors.DispatcherKeyError, dispatcher.disconnect, x, signal='not-registered' ) def getSuite(): return unittest.makeSuite(DispatcherTests,'test') if __name__ == "__main__": unittest.main () PyDispatcher-2.0.5/tests/test_robustapply.py0000644000175000001440000000133112451340306022214 0ustar mcfletchusers00000000000000from pydispatch.robustapply import * import unittest def noArgument(): pass def oneArgument (blah): pass def twoArgument(blah, other): pass class TestCases( unittest.TestCase ): def test01( self ): robustApply(noArgument ) def test02( self ): self.assertRaises( TypeError, robustApply, noArgument, "this" ) def test03( self ): self.assertRaises( TypeError, robustApply, oneArgument ) def test04( self ): """Raise error on duplication of a particular argument""" self.assertRaises( TypeError, robustApply, oneArgument, "this", blah = "that" ) def getSuite(): return unittest.makeSuite(TestCases,'test') if __name__ == "__main__": unittest.main() PyDispatcher-2.0.5/examples/0000755000175000001440000000000012455637705016715 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/examples/__init__.py0000644000175000001440000000006012451340306021002 0ustar mcfletchusers00000000000000"""Example scripts for the dispatch project """ PyDispatcher-2.0.5/examples/extra_args.py0000755000175000001440000000153512451340306021415 0ustar mcfletchusers00000000000000#! /usr/bin/env python from __future__ import print_function from pydispatch import dispatcher SIGNAL = 'my-first-signal' SIGNAL2 = 'my-second-signal' def handle_event( sender ): """Simple event handler""" print('Signal was sent by', sender) dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any ) def handle_specific_event( sender, moo ): """Handle a simple event, requiring a "moo" parameter""" print('Specialized event for %(sender)s moo=%(moo)r'%locals()) dispatcher.connect( handle_specific_event, signal=SIGNAL2, sender=dispatcher.Any ) first_sender = object() second_sender = {} def main( ): dispatcher.send( signal=SIGNAL, sender=first_sender ) dispatcher.send( signal=SIGNAL, sender=second_sender ) dispatcher.send( signal=SIGNAL2, sender=second_sender, moo='this' ) if __name__ == "__main__": main()PyDispatcher-2.0.5/examples/hello_messages.py0000755000175000001440000000077312451340306022253 0ustar mcfletchusers00000000000000#! /usr/bin/env python from __future__ import print_function from pydispatch import dispatcher SIGNAL = 'my-first-signal' def handle_event( sender ): """Simple event handler""" print('Signal was sent by', sender) dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any ) first_sender = object() second_sender = {} def main( ): dispatcher.send( signal=SIGNAL, sender=first_sender ) dispatcher.send( signal=SIGNAL, sender=second_sender ) if __name__ == "__main__": main()PyDispatcher-2.0.5/examples/simple_sample.py0000644000175000001440000000444712451340306022112 0ustar mcfletchusers00000000000000"""Simple sample showing basic usage pattern""" from __future__ import print_function from pydispatch import dispatcher def doSomethingUseful( table, signal, sender ): """Sample method to receive signals""" print(' doSomethingUseful', repr(table), signal, sender) def doSomethingElse( signal, **named ): """Sample method to receive signals This method demonstrates the use of the **named parameter, which allows a method to receive all remaining parameters from the send call. """ print(' doSomethingElse', named) def doDefault( ): """Sample method to receive All signals Note that this function will be registered for all signals from a given object. It does not have the same interface as any of the other functions registered for those signals. The system will automatically determine the appropriate calling signature for the function. """ print(' doDefault (no arguments)') class Node(object): """Sample object to send signals, note lack of dispatcher-aware code""" def __init__( self, name="an object" ): self.name = name def __repr__( self ): return "%s( %r )"%( self.__class__.__name__, self.name ) DO_LOTS = 0 DO_SOMETHING = ('THIS','IS','A','MORE','COMPLEX','SIGNAL') DO_SOMETHING_ELSE = Node() ourObjects = [ Node(), Node(), Node(), ] if __name__ == "__main__": # Establish some "routing" connections dispatcher.connect ( doSomethingUseful, signal = DO_LOTS, sender = ourObjects[0], ) dispatcher.connect ( doSomethingElse, signal = DO_SOMETHING, sender = ourObjects[0], ) dispatcher.connect( doDefault, signal = dispatcher.Any, # this is actually the default, sender = ourObjects[0], ) print("Sending DO_LOTS from first object") dispatcher.send( signal = DO_LOTS, sender = ourObjects[0], table = "Table Argument", ) print("Sending DO_SOMETHING from first object") dispatcher.send( signal = DO_SOMETHING, sender = ourObjects[0], table = "Table Argument", ) print("Sending DO_SOMETHING_ELSE from first object") dispatcher.send( signal = DO_SOMETHING_ELSE, sender = ourObjects[0], table = "Table Argument", )PyDispatcher-2.0.5/PyDispatcher.egg-info/0000755000175000001440000000000012455637705021170 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/PyDispatcher.egg-info/SOURCES.txt0000644000175000001440000000161412455637704023055 0ustar mcfletchusers00000000000000MANIFEST.in license.txt setup.py PyDispatcher.egg-info/PKG-INFO PyDispatcher.egg-info/SOURCES.txt PyDispatcher.egg-info/dependency_links.txt PyDispatcher.egg-info/top_level.txt docs/index.html docs/images/greypinstripe.png docs/pydoc/__init__.py docs/pydoc/builddocs.py docs/pydoc/pydispatch.__init__.html docs/pydoc/pydispatch.dispatcher.html docs/pydoc/pydispatch.errors.html docs/pydoc/pydispatch.html docs/pydoc/pydispatch.robust.html docs/pydoc/pydispatch.robustapply.html docs/pydoc/pydispatch.saferef.html docs/pydoc/pydoc2.py docs/pydoc/weakref.html docs/style/sitestyle.css examples/__init__.py examples/extra_args.py examples/hello_messages.py examples/simple_sample.py pydispatch/__init__.py pydispatch/dispatcher.py pydispatch/errors.py pydispatch/robust.py pydispatch/robustapply.py pydispatch/saferef.py tests/__init__.py tests/test_dispatcher.py tests/test_robustapply.py tests/test_saferef.pyPyDispatcher-2.0.5/PyDispatcher.egg-info/top_level.txt0000644000175000001440000000001312455637704023713 0ustar mcfletchusers00000000000000pydispatch PyDispatcher-2.0.5/PyDispatcher.egg-info/dependency_links.txt0000644000175000001440000000000112455637704025235 0ustar mcfletchusers00000000000000 PyDispatcher-2.0.5/PyDispatcher.egg-info/PKG-INFO0000644000175000001440000000231412455637704022264 0ustar mcfletchusers00000000000000Metadata-Version: 1.1 Name: PyDispatcher Version: 2.0.5 Summary: Multi-producer-multi-consumer signal dispatching mechanism Home-page: http://pydispatcher.sourceforge.net Author: Mike C. Fletcher Author-email: pydispatcher-devel@lists.sourceforge.net License: BSD Description: Dispatcher mechanism for creating event models PyDispatcher is an enhanced version of Patrick K. O'Brien's original dispatcher.py module. It provides the Python programmer with a robust mechanism for event routing within various application contexts. Included in the package are the robustapply and saferef modules, which provide the ability to selectively apply arguments to callable objects and to reference instance methods using weak-references. Keywords: dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply Platform: Any Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Intended Audience :: Developers PyDispatcher-2.0.5/MANIFEST.in0000644000175000001440000000050612451340306016616 0ustar mcfletchusers00000000000000include MANIFEST.in include license.txt include *.py recursive-include docs *.html recursive-include docs/images *.png recursive-include docs/style *.css recursive-include docs/pydoc *.html *.py recursive-include examples *.py recursive-include tests *.py global-exclude *.bat global-exclude ./CVS global-exclude .cvsignore PyDispatcher-2.0.5/docs/0000755000175000001440000000000012455637705016027 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/docs/pydoc/0000755000175000001440000000000012455637705017145 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/docs/pydoc/pydispatch.dispatcher.html0000644000175000001440000005432112455637632024334 0ustar mcfletchusers00000000000000 Python: module pydispatch.dispatcher
 
 
pydispatch.dispatcher
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/dispatcher.py

Multiple-producer-multiple-consumer signal-dispatching
 
dispatcher is the core of the PyDispatcher system,
providing the primary API and the core logic for the
system.
 
Module attributes of note:
 
    Any -- Singleton used to signal either "Any Sender" or
        "Any Signal".  See documentation of the _Any class.
    Anonymous -- Singleton used to signal "Anonymous Sender"
        See documentation of the _Anonymous class.
 
Internal attributes:
    WEAKREF_TYPES -- tuple of types/classes which represent
        weak references to receivers, and thus must be de-
        referenced on retrieval to retrieve the callable
        object
    connections -- { senderkey (id) : { signal : [receivers...]}}
    senders -- { senderkey (id) : weakref(sender) }
        used for cleaning up sender references on sender
        deletion
    sendersBack -- { receiverkey (id) : [senderkey (id)...] }
        used for cleaning up receiver references on receiver
        deletion, (considerably speeds up the cleanup process
        vs. the original code.)

 
Modules
       
pydispatch.errors
pydispatch.robustapply
pydispatch.saferef
weakref

 
Classes
       
_Parameter
_Anonymous
_Any

 
class _Anonymous(_Parameter)
    Singleton used to signal "Anonymous Sender"
 
The Anonymous object is used to signal that the sender
of a message is not specified (as distinct from being
"any sender").  Registering callbacks for Anonymous
will only receive messages sent without senders.  Sending
with anonymous will only send messages to those receivers
registered for Any or Anonymous.
 
Note:
    The default sender for connect is Any, while the
    default sender for send is Anonymous.  This has
    the effect that if you do not specify any senders
    in either function then all messages are routed
    as though there was a single sender (Anonymous)
    being used everywhere.
 
  Methods inherited from _Parameter:
__repr__(self)

 
class _Any(_Parameter)
    Singleton used to signal either "Any Sender" or "Any Signal"
 
The Any object can be used with connect, disconnect,
send, or sendExact to signal that the parameter given
Any should react to all senders/signals, not just
a particular sender/signal.
 
  Methods inherited from _Parameter:
__repr__(self)

 
class _Parameter
    Used to represent default parameter values.
 
  Methods defined here:
__repr__(self)

 
Functions
       
_cleanupConnections(senderkey, signal)
Delete any empty signals for senderkey. Delete senderkey if empty.
_killBackref(receiver, senderkey)
Do the actual removal of back reference from receiver to senderkey
_removeBackrefs(senderkey)
Remove all back-references to this senderkey
_removeOldBackRefs(senderkey, signal, receiver, receivers)
Kill old sendersBack references from receiver
 
This guards against multiple registration of the same
receiver for a given signal and sender leaking memory
as old back reference records build up.
 
Also removes old receiver instance from receivers
_removeReceiver(receiver)
Remove receiver from connections.
_removeSender(senderkey)
Remove senderkey from connections.
connect(receiver, signal=_Any, sender=_Any, weak=True)
Connect receiver to sender for signal
 
receiver -- a callable Python object which is to receive
    messages/signals/events.  Receivers must be hashable
    objects.
 
    if weak is True, then receiver must be weak-referencable
    (more precisely saferef.safeRef() must be able to create
    a reference to the receiver).
 
    Receivers are fairly flexible in their specification,
    as the machinery in the robustApply module takes care
    of most of the details regarding figuring out appropriate
    subsets of the sent arguments to apply to a given
    receiver.
 
    Note:
        if receiver is itself a weak reference (a callable),
        it will be de-referenced by the system's machinery,
        so *generally* weak references are not suitable as
        receivers, though some use might be found for the
        facility whereby a higher-level library passes in
        pre-weakrefed receiver references.
 
signal -- the signal to which the receiver should respond
 
    if Any, receiver will receive any signal from the
    indicated sender (which might also be Any, but is not
    necessarily Any).
    
    Otherwise must be a hashable Python object other than
    None (DispatcherError raised on None).
    
sender -- the sender to which the receiver should respond
 
    if Any, receiver will receive the indicated signals
    from any sender.
    
    if Anonymous, receiver will only receive indicated
    signals from send/sendExact which do not specify a
    sender, or specify Anonymous explicitly as the sender.
 
    Otherwise can be any python object.
    
weak -- whether to use weak references to the receiver
    By default, the module will attempt to use weak
    references to the receiver objects.  If this parameter
    is false, then strong references will be used.
 
returns None, may raise DispatcherTypeError
disconnect(receiver, signal=_Any, sender=_Any, weak=True)
Disconnect receiver from sender for signal
 
receiver -- the registered receiver to disconnect
signal -- the registered signal to disconnect
sender -- the registered sender to disconnect
weak -- the weakref state to disconnect
 
disconnect reverses the process of connect,
the semantics for the individual elements are
logically equivalent to a tuple of
(receiver, signal, sender, weak) used as a key
to be deleted from the internal routing tables.
(The actual process is slightly more complex
but the semantics are basically the same).
 
Note:
    Using disconnect is not required to cleanup
    routing when an object is deleted, the framework
    will remove routes for deleted objects
    automatically.  It's only necessary to disconnect
    if you want to stop routing to a live object.
    
returns None, may raise DispatcherTypeError or
    DispatcherKeyError
getAllReceivers(sender=_Any, signal=_Any)
Get list of all receivers from global tables
 
This gets all receivers which should receive
the given signal from sender, each receiver should
be produced only once by the resulting generator
getReceivers(sender=_Any, signal=_Any)
Get list of receivers from global tables
 
This utility function allows you to retrieve the
raw list of receivers from the connections table
for the given sender and signal pair.
 
Note:
    there is no guarantee that this is the actual list
    stored in the connections table, so the value
    should be treated as a simple iterable/truth value
    rather than, for instance a list to which you
    might append new records.
 
Normally you would use liveReceiversgetReceivers( ...))
to retrieve the actual receiver objects as an iterable
object.
liveReceivers(receivers)
Filter sequence of receivers to get resolved, live receivers
 
This is a generator which will iterate over
the passed sequence, checking for weak references
and resolving them, then returning all live
receivers.
send(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal from sender to all connected receivers.
 
signal -- (hashable) signal value, see connect for details
 
sender -- the sender of the signal
 
    if Any, only receivers registered for Any will receive
    the message.
 
    if Anonymous, only receivers registered to receive
    messages from Anonymous or Any will receive the message
 
    Otherwise can be any python object (normally one
    registered with a connect if you actually want
    something to occur).
 
arguments -- positional arguments which will be passed to
    *all* receivers. Note that this may raise TypeErrors
    if the receivers do not allow the particular arguments.
    Note also that arguments are applied before named
    arguments, so they should be used with care.
 
named -- named arguments which will be filtered according
    to the parameters of the receivers to only provide those
    acceptable to the receiver.
 
Return a list of tuple pairs [(receiver, response), ... ]
 
if any receiver raises an error, the error propagates back
through send, terminating the dispatch loop, so it is quite
possible to not have all receivers called if a raises an
error.
sendExact(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal only to those receivers registered for exact message
 
sendExact allows for avoiding Any/Anonymous registered
handlers, sending only to those receivers explicitly
registered for a particular signal on a particular
sender.

 
Data
        Anonymous = _Anonymous
Any = _Any
WEAKREF_TYPES = (<type 'weakref'>, <class 'pydispatch.saferef.BoundMethodWeakref'>)
__file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/dispatcher.py'
__name__ = 'pydispatch.dispatcher'
__package__ = 'pydispatch'
connections = {}
senders = {}
sendersBack = {}
PyDispatcher-2.0.5/docs/pydoc/weakref.html0000644000175000001440000004542612455637632021471 0ustar mcfletchusers00000000000000 Python: module weakref
 
 
weakref
index
/usr/lib/python2.7/weakref.py

Weak reference support for Python.
 
This module is an implementation of PEP 205:
 
http://www.python.org/dev/peps/pep-0205/

 
Modules
       
UserDict

 
Classes
       
UserDict
WeakKeyDictionary
WeakValueDictionary
__builtin__.weakref(object)
KeyedRef

 
class KeyedRef(__builtin__.weakref)
    Specialized reference that includes a key corresponding to the value.
 
This is used in the WeakValueDictionary to avoid having to create
a function object for each key stored in the mapping.  A shared
callback object can use the 'key' attribute of a KeyedRef instead
of getting a reference to the key from an enclosing scope.
 
 
Method resolution order:
KeyedRef
__builtin__.weakref
object

Methods defined here:
__init__(self, ob, callback, key)

Static methods defined here:
__new__(type, ob, callback, key)

Data descriptors defined here:
key

Methods inherited from __builtin__.weakref:
__call__(...)
x.__call__(...) <==> x(...)
__eq__(...)
x.__eq__(y) <==> x==y
__ge__(...)
x.__ge__(y) <==> x>=y
__gt__(...)
x.__gt__(y) <==> x>y
__hash__(...)
x.__hash__() <==> hash(x)
__le__(...)
x.__le__(y) <==> x<=y
__lt__(...)
x.__lt__(y) <==> x<y
__ne__(...)
x.__ne__(y) <==> x!=y
__repr__(...)
x.__repr__() <==> repr(x)

 
class WeakKeyDictionary(UserDict)
    Mapping class that references keys weakly.
 
Entries in the dictionary will be discarded when there is no
longer a strong reference to the key. This can be used to
associate additional data with an object owned by other parts of
an application without adding attributes to those objects. This
can be especially useful with objects that override attribute
accesses.
 
  Methods defined here:
__contains__(self, key)
__copy__ = copy(self)
__deepcopy__(self, memo)
__delitem__(self, key)
__getitem__(self, key)
__init__(self, dict=None)
__iter__ = iterkeys(self)
__repr__(self)
__setitem__(self, key, value)
copy(self)
get(self, key, default=None)
has_key(self, key)
items(self)
iteritems(self)
iterkeyrefs(self)
Return an iterator that yields the weak references to the keys.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
iterkeys(self)
itervalues(self)
keyrefs(self)
Return a list of weak references to the keys.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
keys(self)
pop(self, key, *args)
popitem(self)
setdefault(self, key, default=None)
update(self, dict=None, **kwargs)

Methods inherited from UserDict:
__cmp__(self, dict)
__len__(self)
clear(self)
values(self)

Class methods inherited from UserDict:
fromkeys(cls, iterable, value=None) from __builtin__.classobj

Data and other attributes inherited from UserDict:
__hash__ = None

 
class WeakValueDictionary(UserDict)
    Mapping class that references values weakly.
 
Entries in the dictionary will be discarded when no strong
reference to the value exists anymore
 
  Methods defined here:
__contains__(self, key)
__copy__ = copy(self)
__deepcopy__(self, memo)
__delitem__(self, key)
__getitem__(self, key)
__init__(self, *args, **kw)
__iter__ = iterkeys(self)
__repr__(self)
__setitem__(self, key, value)
clear(self)
copy(self)
get(self, key, default=None)
has_key(self, key)
items(self)
iteritems(self)
iterkeys(self)
itervaluerefs(self)
Return an iterator that yields the weak references to the values.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
itervalues(self)
pop(self, key, *args)
popitem(self)
setdefault(self, key, default=None)
update(self, dict=None, **kwargs)
valuerefs(self)
Return a list of weak references to the values.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
values(self)

Methods inherited from UserDict:
__cmp__(self, dict)
__len__(self)
keys(self)

Class methods inherited from UserDict:
fromkeys(cls, iterable, value=None) from __builtin__.classobj

Data and other attributes inherited from UserDict:
__hash__ = None

 
Functions
       
getweakrefcount(...)
getweakrefcount(object) -- return the number of weak references
to 'object'.
getweakrefs(...)
getweakrefs(object) -- return a list of all weak reference objects
that point to 'object'.
proxy(...)
proxy(object[, callback]) -- create a proxy object that weakly
references 'object'.  'callback', if given, is called with a
reference to the proxy when 'object' is about to be finalized.

 
Data
        ProxyTypes = (<type 'weakproxy'>, <type 'weakcallableproxy'>)
__all__ = ['ref', 'proxy', 'getweakrefcount', 'getweakrefs', 'WeakKeyDictionary', 'ReferenceError', 'ReferenceType', 'ProxyType', 'CallableProxyType', 'ProxyTypes', 'WeakValueDictionary', 'WeakSet']
__file__ = '/usr/lib/python2.7/weakref.pyc'
__name__ = 'weakref'
PyDispatcher-2.0.5/docs/pydoc/__init__.py0000644000175000001440000000045612451340306021243 0ustar mcfletchusers00000000000000"""pydoc documentation system with enhancements and automatic local builder This package is based on the standard pydoc package, with a few minor enhancements, and a slightly modified format. An automatic mechanism for generating extensive documentation for the OpenGLContext project is provided. """PyDispatcher-2.0.5/docs/pydoc/builddocs.py0000755000175000001440000000104412451340306021451 0ustar mcfletchusers00000000000000#! /usr/bin/env python """Script to automatically generate OpenGLContext documentation""" import pydoc2 if __name__ == "__main__": excludes = [ "math", "string", ] stops = [ "OpenGL.Demo.NeHe", "OpenGL.Demo.GLE", "OpenGL.Demo.da", ] modules = [ "pydispatch", "weakref", ] pydoc2.PackageDocumentationGenerator( baseModules = modules, destinationDirectory = ".", exclusions = excludes, recursionStops = stops, ).process () PyDispatcher-2.0.5/docs/pydoc/pydoc2.py0000644000175000001440000003741012451340306020704 0ustar mcfletchusers00000000000000"""Pydoc sub-class for generating documentation for entire packages""" import pydoc, inspect, os, string import sys, imp, os, stat, re, types, inspect from repr import Repr from string import expandtabs, find, join, lower, split, strip, rfind, rstrip class DefaultFormatter(pydoc.HTMLDoc): def docmodule(self, object, name=None, mod=None, packageContext = None, *ignored): """Produce HTML documentation for a module object.""" name = object.__name__ # ignore the passed-in name parts = split(name, '.') links = [] for i in range(len(parts)-1): links.append( '%s' % (join(parts[:i+1], '.'), parts[i])) linkedname = join(links + parts[-1:], '.') head = '%s' % linkedname try: path = inspect.getabsfile(object) url = path if sys.platform == 'win32': import nturl2path url = nturl2path.pathname2url(path) filelink = '%s' % (url, path) except TypeError: filelink = '(built-in)' info = [] if hasattr(object, '__version__'): version = str(object.__version__) if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = strip(version[11:-1]) info.append('version %s' % self.escape(version)) if hasattr(object, '__date__'): info.append(self.escape(str(object.__date__))) if info: head = head + ' (%s)' % join(info, ', ') result = self.heading( head, '#ffffff', '#7799ee', 'index
' + filelink) modules = inspect.getmembers(object, inspect.ismodule) classes, cdict = [], {} for key, value in inspect.getmembers(object, inspect.isclass): if (inspect.getmodule(value) or object) is object: classes.append((key, value)) cdict[key] = cdict[value] = '#' + key for key, value in classes: for base in value.__bases__: key, modname = base.__name__, base.__module__ module = sys.modules.get(modname) if modname != name and module and hasattr(module, key): if getattr(module, key) is base: if not cdict.has_key(key): cdict[key] = cdict[base] = modname + '.html#' + key funcs, fdict = [], {} for key, value in inspect.getmembers(object, inspect.isroutine): if inspect.isbuiltin(value) or inspect.getmodule(value) is object: funcs.append((key, value)) fdict[key] = '#-' + key if inspect.isfunction(value): fdict[value] = fdict[key] data = [] for key, value in inspect.getmembers(object, pydoc.isdata): if key not in ['__builtins__', '__doc__']: data.append((key, value)) doc = self.markup(pydoc.getdoc(object), self.preformat, fdict, cdict) doc = doc and '%s' % doc result = result + '

%s

\n' % doc packageContext.clean ( classes, object ) packageContext.clean ( funcs, object ) packageContext.clean ( data, object ) if hasattr(object, '__path__'): modpkgs = [] modnames = [] for file in os.listdir(object.__path__[0]): path = os.path.join(object.__path__[0], file) modname = inspect.getmodulename(file) if modname and modname not in modnames: modpkgs.append((modname, name, 0, 0)) modnames.append(modname) elif pydoc.ispackage(path): modpkgs.append((file, name, 1, 0)) modpkgs.sort() contents = self.multicolumn(modpkgs, self.modpkglink) ## result = result + self.bigsection( ## 'Package Contents', '#ffffff', '#aa55cc', contents) result = result + self.moduleSection( object, packageContext) elif modules: contents = self.multicolumn( modules, lambda (key, value), s=self: s.modulelink(value)) result = result + self.bigsection( 'Modules', '#fffff', '#aa55cc', contents) if classes: classlist = map(lambda (key, value): value, classes) contents = [ self.formattree(inspect.getclasstree(classlist, 1), name)] for key, value in classes: contents.append(self.document(value, key, name, fdict, cdict)) result = result + self.bigsection( 'Classes', '#ffffff', '#ee77aa', join(contents)) if funcs: contents = [] for key, value in funcs: contents.append(self.document(value, key, name, fdict, cdict)) result = result + self.bigsection( 'Functions', '#ffffff', '#eeaa77', join(contents)) if data: contents = [] for key, value in data: contents.append(self.document(value, key)) result = result + self.bigsection( 'Data', '#ffffff', '#55aa55', join(contents, '
\n')) if hasattr(object, '__author__'): contents = self.markup(str(object.__author__), self.preformat) result = result + self.bigsection( 'Author', '#ffffff', '#7799ee', contents) if hasattr(object, '__credits__'): contents = self.markup(str(object.__credits__), self.preformat) result = result + self.bigsection( 'Credits', '#ffffff', '#7799ee', contents) return result def classlink(self, object, modname): """Make a link for a class.""" name, module = object.__name__, sys.modules.get(object.__module__) if hasattr(module, name) and getattr(module, name) is object: return '%s' % ( module.__name__, name, name ) return pydoc.classname(object, modname) def moduleSection( self, object, packageContext ): """Create a module-links section for the given object (module)""" modules = inspect.getmembers(object, inspect.ismodule) packageContext.clean ( modules, object ) packageContext.recurseScan( modules ) if hasattr(object, '__path__'): modpkgs = [] modnames = [] for file in os.listdir(object.__path__[0]): path = os.path.join(object.__path__[0], file) modname = inspect.getmodulename(file) if modname and modname not in modnames: modpkgs.append((modname, object.__name__, 0, 0)) modnames.append(modname) elif pydoc.ispackage(path): modpkgs.append((file, object.__name__, 1, 0)) modpkgs.sort() # do more recursion here... for (modname, name, ya,yo) in modpkgs: packageContext.addInteresting( join( (object.__name__, modname), '.')) items = [] for (modname, name, ispackage,isshadowed) in modpkgs: try: # get the actual module object... ## if modname == "events": ## import pdb ## pdb.set_trace() module = pydoc.safeimport( "%s.%s"%(name,modname) ) description, documentation = pydoc.splitdoc( inspect.getdoc( module )) if description: items.append( """%s -- %s"""% ( self.modpkglink( (modname, name, ispackage, isshadowed) ), description, ) ) else: items.append( self.modpkglink( (modname, name, ispackage, isshadowed) ) ) except: items.append( self.modpkglink( (modname, name, ispackage, isshadowed) ) ) contents = string.join( items, '
') result = self.bigsection( 'Package Contents', '#ffffff', '#aa55cc', contents) elif modules: contents = self.multicolumn( modules, lambda (key, value), s=self: s.modulelink(value)) result = self.bigsection( 'Modules', '#fffff', '#aa55cc', contents) else: result = "" return result class AlreadyDone(Exception): pass class PackageDocumentationGenerator: """A package document generator creates documentation for an entire package using pydoc's machinery. baseModules -- modules which will be included and whose included and children modules will be considered fair game for documentation destinationDirectory -- the directory into which the HTML documentation will be written recursion -- whether to add modules which are referenced by and/or children of base modules exclusions -- a list of modules whose contents will not be shown in any other module, commonly such modules as OpenGL.GL, wxPython.wx etc. recursionStops -- a list of modules which will explicitly stop recursion (i.e. they will never be included), even if they are children of base modules. formatter -- allows for passing in a custom formatter see DefaultFormatter for sample implementation. """ def __init__ ( self, baseModules, destinationDirectory = ".", recursion = 1, exclusions = (), recursionStops = (), formatter = None ): self.destinationDirectory = os.path.abspath( destinationDirectory) self.exclusions = {} self.warnings = [] self.baseSpecifiers = {} self.completed = {} self.recursionStops = {} self.recursion = recursion for stop in recursionStops: self.recursionStops[ stop ] = 1 self.pending = [] for exclusion in exclusions: try: self.exclusions[ exclusion ]= pydoc.locate ( exclusion) except pydoc.ErrorDuringImport, value: self.warn( """Unable to import the module %s which was specified as an exclusion module"""% (repr(exclusion))) self.formatter = formatter or DefaultFormatter() for base in baseModules: self.addBase( base ) def warn( self, message ): """Warnings are used for recoverable, but not necessarily ignorable conditions""" self.warnings.append (message) def info (self, message): """Information/status report""" print message def addBase(self, specifier): """Set the base of the documentation set, only children of these modules will be documented""" try: self.baseSpecifiers [specifier] = pydoc.locate ( specifier) self.pending.append (specifier) except pydoc.ErrorDuringImport, value: self.warn( """Unable to import the module %s which was specified as a base module"""% (repr(specifier))) def addInteresting( self, specifier): """Add a module to the list of interesting modules""" if self.checkScope( specifier): ## print "addInteresting", specifier self.pending.append (specifier) else: self.completed[ specifier] = 1 def checkScope (self, specifier): """Check that the specifier is "in scope" for the recursion""" if not self.recursion: return 0 items = string.split (specifier, ".") stopCheck = items [:] while stopCheck: name = string.join(items, ".") if self.recursionStops.get( name): return 0 elif self.completed.get (name): return 0 del stopCheck[-1] while items: if self.baseSpecifiers.get( string.join(items, ".")): return 1 del items[-1] # was not within any given scope return 0 def process( self ): """Having added all of the base and/or interesting modules, proceed to generate the appropriate documentation for each module in the appropriate directory, doing the recursion as we go.""" try: while self.pending: try: if self.completed.has_key( self.pending[0] ): raise AlreadyDone( self.pending[0] ) self.info( """Start %s"""% (repr(self.pending[0]))) object = pydoc.locate ( self.pending[0] ) self.info( """ ... found %s"""% (repr(object.__name__))) except AlreadyDone: pass except pydoc.ErrorDuringImport, value: self.info( """ ... FAILED %s"""% (repr( value))) self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) except (SystemError, SystemExit), value: self.info( """ ... FAILED %s"""% (repr( value))) self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) except Exception, value: self.info( """ ... FAILED %s"""% (repr( value))) self.warn( """Unable to import the module %s"""% (repr(self.pending[0]))) else: page = self.formatter.page( pydoc.describe(object), self.formatter.docmodule( object, object.__name__, packageContext = self, ) ) file = open ( os.path.join( self.destinationDirectory, self.pending[0] + ".html", ), 'w', ) file.write(page) file.close() self.completed[ self.pending[0]] = object del self.pending[0] finally: for item in self.warnings: print item def clean (self, objectList, object): """callback from the formatter object asking us to remove those items in the key, value pairs where the object is imported from one of the excluded modules""" for key, value in objectList[:]: for excludeObject in self.exclusions.values(): if hasattr( excludeObject, key ) and excludeObject is not object: if ( getattr( excludeObject, key) is value or (hasattr( excludeObject, '__name__') and excludeObject.__name__ == "Numeric" ) ): objectList[:] = [ (k,o) for k,o in objectList if k != key ] def recurseScan(self, objectList): """Process the list of modules trying to add each to the list of interesting modules""" for key, value in objectList: self.addInteresting( value.__name__ ) if __name__ == "__main__": excludes = [ "OpenGL.GL", "OpenGL.GLU", "OpenGL.GLUT", "OpenGL.GLE", "OpenGL.GLX", "wxPython.wx", "Numeric", "_tkinter", "Tkinter", ] modules = [ "OpenGLContext.debug", ## "wxPython.glcanvas", ## "OpenGL.Tk", ## "OpenGL", ] PackageDocumentationGenerator( baseModules = modules, destinationDirectory = "z:\\temp", exclusions = excludes, ).process () PyDispatcher-2.0.5/docs/pydoc/pydispatch.__init__.html0000644000175000001440000000366012455637632023745 0ustar mcfletchusers00000000000000 Python: module pydispatch.__init__
 
 
pydispatch.__init__ (version 2.0.5)
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/__init__.py

Multi-consumer multi-producer dispatching mechanism

 
Data
        __author__ = "Patrick K. O'Brien"
__file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/__init__.pyc'
__license__ = 'BSD-style, see license.txt for details'
__name__ = 'pydispatch.__init__'
__version__ = '2.0.5'

 
Author
        Patrick K. O'Brien
PyDispatcher-2.0.5/docs/pydoc/pydispatch.html0000644000175000001440000000560212455637632022205 0ustar mcfletchusers00000000000000 Python: package pydispatch
 
 
pydispatch (version 2.0.5)
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/__init__.py

Multi-consumer multi-producer dispatching mechanism

 
Package Contents
        __init__ -- Multi-consumer multi-producer dispatching mechanism
dispatcher -- Multiple-producer-multiple-consumer signal-dispatching
errors -- Error types for dispatcher mechanism
robust -- Module implementing error-catching version of send (sendRobust)
robustapply -- Robust apply mechanism
saferef -- Refactored "safe reference" from dispatcher.py

 
Data
        __author__ = "Patrick K. O'Brien"
__file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/__init__.py'
__license__ = 'BSD-style, see license.txt for details'
__name__ = 'pydispatch'
__path__ = ['/mnt/homevar/var/pylive/pydispatcher/pydispatch']
__version__ = '2.0.5'

 
Author
        Patrick K. O'Brien
PyDispatcher-2.0.5/docs/pydoc/pydispatch.robust.html0000644000175000001440000001043012455637632023515 0ustar mcfletchusers00000000000000 Python: module pydispatch.robust
 
 
pydispatch.robust
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/robust.py

Module implementing error-catching version of send (sendRobust)

 
Functions
       
sendRobust(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal from sender to all connected receivers catching errors
 
signal -- (hashable) signal value, see connect for details
 
sender -- the sender of the signal
 
    if Any, only receivers registered for Any will receive
    the message.
 
    if Anonymous, only receivers registered to receive
    messages from Anonymous or Any will receive the message
 
    Otherwise can be any python object (normally one
    registered with a connect if you actually want
    something to occur).
 
arguments -- positional arguments which will be passed to
    *all* receivers. Note that this may raise TypeErrors
    if the receivers do not allow the particular arguments.
    Note also that arguments are applied before named
    arguments, so they should be used with care.
 
named -- named arguments which will be filtered according
    to the parameters of the receivers to only provide those
    acceptable to the receiver.
 
Return a list of tuple pairs [(receiver, response), ... ]
 
if any receiver raises an error (specifically any subclass of Exception),
the error instance is returned as the result for that receiver.

 
Data
        Anonymous = _Anonymous
Any = _Any
__file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/robust.py'
__name__ = 'pydispatch.robust'
__package__ = 'pydispatch'
PyDispatcher-2.0.5/docs/pydoc/pydispatch.errors.html0000644000175000001440000003700312455637632023520 0ustar mcfletchusers00000000000000 Python: module pydispatch.errors
 
 
pydispatch.errors
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/errors.py

Error types for dispatcher mechanism

 
Classes
       
Exception(BaseException)
DispatcherError
DispatcherKeyError(KeyError, DispatcherError)
DispatcherTypeError(TypeError, DispatcherError)
KeyError(LookupError)
DispatcherKeyError(KeyError, DispatcherError)
TypeError(StandardError)
DispatcherTypeError(TypeError, DispatcherError)

 
class DispatcherError(Exception)
    Base class for all Dispatcher errors
 
 
Method resolution order:
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from Exception:
__init__(...)
x.__init__(...) initializes x; see help(type(x)) for signature

Data and other attributes inherited from Exception:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

Methods inherited from BaseException:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]
 
Use of negative indices is not supported.
__reduce__(...)
__repr__(...)
x.__repr__() <==> repr(x)
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
__setstate__(...)
__str__(...)
x.__str__() <==> str(x)
__unicode__(...)

Data descriptors inherited from BaseException:
__dict__
args
message

 
class DispatcherKeyError(KeyError, DispatcherError)
    Error raised when unknown (sender,signal) set specified
 
 
Method resolution order:
DispatcherKeyError
KeyError
LookupError
StandardError
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from KeyError:
__init__(...)
x.__init__(...) initializes x; see help(type(x)) for signature
__str__(...)
x.__str__() <==> str(x)

Data and other attributes inherited from KeyError:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

Methods inherited from BaseException:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]
 
Use of negative indices is not supported.
__reduce__(...)
__repr__(...)
x.__repr__() <==> repr(x)
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
__setstate__(...)
__unicode__(...)

Data descriptors inherited from BaseException:
__dict__
args
message

 
class DispatcherTypeError(TypeError, DispatcherError)
    Error raised when inappropriate signal-type specified (None)
 
 
Method resolution order:
DispatcherTypeError
TypeError
StandardError
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from TypeError:
__init__(...)
x.__init__(...) initializes x; see help(type(x)) for signature

Data and other attributes inherited from TypeError:
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T

Methods inherited from BaseException:
__delattr__(...)
x.__delattr__('name') <==> del x.name
__getattribute__(...)
x.__getattribute__('name') <==> x.name
__getitem__(...)
x.__getitem__(y) <==> x[y]
__getslice__(...)
x.__getslice__(i, j) <==> x[i:j]
 
Use of negative indices is not supported.
__reduce__(...)
__repr__(...)
x.__repr__() <==> repr(x)
__setattr__(...)
x.__setattr__('name', value) <==> x.name = value
__setstate__(...)
__str__(...)
x.__str__() <==> str(x)
__unicode__(...)

Data descriptors inherited from BaseException:
__dict__
args
message

 
Data
        __file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/errors.py'
__name__ = 'pydispatch.errors'
PyDispatcher-2.0.5/docs/pydoc/pydispatch.saferef.html0000644000175000001440000003153212455637632023620 0ustar mcfletchusers00000000000000 Python: module pydispatch.saferef
 
 
pydispatch.saferef
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/saferef.py

Refactored "safe reference" from dispatcher.py

 
Modules
       
sys
traceback
weakref

 
Classes
       
object
BoundMethodWeakref

 
class BoundMethodWeakref(object)
    'Safe' and reusable weak references to instance methods
 
BoundMethodWeakref objects provide a mechanism for
referencing a bound method without requiring that the
method object itself (which is normally a transient
object) is kept alive.  Instead, the BoundMethodWeakref
object keeps weak references to both the object and the
function which together define the instance method.
 
Attributes:
    key -- the identity key for the reference, calculated
        by the class's calculateKey method applied to the
        target instance method
    deletionMethods -- sequence of callable objects taking
        single argument, a reference to this object which
        will be called when *either* the target object or
        target function is garbage collected (i.e. when
        this object becomes invalid).  These are specified
        as the onDelete parameters of safeRef calls.
    weakSelf -- weak reference to the target object
    weakFunc -- weak reference to the target function
 
Class Attributes:
    _allInstances -- class attribute pointing to all live
        BoundMethodWeakref objects indexed by the class's
        calculateKey(target) method applied to the target
        objects.  This weak value dictionary is used to
        short-circuit creation so that multiple references
        to the same (object, function) pair produce the
        same BoundMethodWeakref instance.
 
  Methods defined here:
__bool__ = __nonzero__(self)
__call__(self)
Return a strong reference to the bound method
 
If the target cannot be retrieved, then will
return None, otherwise returns a bound instance
method for our object and function.
 
Note:
    You may call this method any number of times,
    as it does not invalidate the reference.
__cmp__(self, other)
Compare with another reference
__init__(self, target, onDelete=None)
Return a weak-reference-like instance for a bound method
 
target -- the instance-method target for the weak
    reference, must have <im_self> and <im_func> attributes
    and be reconstructable via:
        target.<im_func>.__get__( target.<im_self> )
    which is true of built-in instance methods.
onDelete -- optional callback which will be called
    when this weak reference ceases to be valid
    (i.e. either the object or the function is garbage
    collected).  Should take a single argument,
    which will be passed a pointer to this object.
__nonzero__(self)
Whether we are still a valid reference
__repr__ = __str__(self)
__str__(self)
Give a friendly representation of the object

Class methods defined here:
calculateKey(cls, target) from type
Calculate the reference key for this reference
 
Currently this is a two-tuple of the id()'s of the
target object and the target function respectively.

Static methods defined here:
__new__(cls, target, onDelete=None, *arguments, **named)
Create new instance or return current instance
 
Basically this method of construction allows us to
short-circuit creation of references to already-
referenced instance methods.  The key corresponding
to the target is calculated, and if there is already
an existing reference, that is returned, with its
deletionMethods attribute updated.  Otherwise the
new instance is created and registered in the table
of already-referenced methods.

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Functions
       
safeRef(target, onDelete=None)
Return a *safe* weak reference to a callable target
 
target -- the object to be weakly referenced, if it's a
    bound method reference, will create a BoundMethodWeakref,
    otherwise creates a simple weakref.
onDelete -- if provided, will have a hard reference stored
    to the callable to be called after the safe reference
    goes out of scope with the reference object, (either a
    weakref or a BoundMethodWeakref) as argument.

 
Data
        __file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/saferef.py'
__name__ = 'pydispatch.saferef'
__package__ = 'pydispatch'
im_func = 'im_func'
im_self = 'im_self'
PyDispatcher-2.0.5/docs/pydoc/pydispatch.robustapply.html0000644000175000001440000000665012455637632024574 0ustar mcfletchusers00000000000000 Python: module pydispatch.robustapply
 
 
pydispatch.robustapply
index
/mnt/homevar/var/pylive/pydispatcher/pydispatch/robustapply.py

Robust apply mechanism
 
Provides a function "call", which can sort out
what arguments a given callable object can take,
and subset the given arguments to match only
those which are acceptable.

 
Modules
       
sys

 
Functions
       
function(receiver)
Get function-like callable object for given receiver
 
returns (function_or_method, codeObject, fromMethod)
 
If fromMethod is true, then the callable already
has its first argument bound
robustApply(receiver, *arguments, **named)
Call receiver with arguments and an appropriate subset of named

 
Data
        __file__ = '/mnt/homevar/var/pylive/pydispatcher/pydispatch/robustapply.py'
__name__ = 'pydispatch.robustapply'
__package__ = 'pydispatch'
func_code = 'func_code'
im_code = 'im_code'
im_func = 'im_func'
im_self = 'im_self'
PyDispatcher-2.0.5/docs/style/0000755000175000001440000000000012455637705017167 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/docs/style/sitestyle.css0000644000175000001440000000164512451340306021714 0ustar mcfletchusers00000000000000h1,h2,h3 { color: #111144; background-image: url(../images/greypinstripe.png); border-top-style: solid; border-top-width: 1 } .footer { color: #111144; background-image: url(../images/greypinstripe.png); text-align: center; border-bottom-style: solid; border-bottom-width: 1 } th { color: #111144; background-image: url(../images/greypinstripe.png); text-align: center; } .introduction { margin-left: 60; margin-right: 60; color: #555555; } .technical { margin-left: 60; margin-right: 60; color: #557755; } p { margin-left: 10; margin-right: 10; } ul { margin-left: 30; } pre { background-color: #ffffcc; margin-left: 60; } blockquote { margin-left: 90; } body { background-color: #FFFFFF; color: #000000; font-family: Arial, Helvetica; } a:link { color: #3333e0; text-decoration: none; } a:visited { color: #1111aa; text-decoration: none; } a:active { color: #111133; text-decoration: none; } PyDispatcher-2.0.5/docs/index.html0000644000175000001440000002764212455637252020034 0ustar mcfletchusers00000000000000 Python Dispatch Package

PyDispatcher

PyDispatcher provides the Python programmer with a multiple-producer-multiple-consumer signal-registration and routing infrastructure for use in multiple contexts.  The mechanism of PyDispatcher started life as a highly rated recipe in the Python Cookbook.  The project aims to include various enhancements to the recipe developed during use in various applications.  It is primarily maintained by Mike Fletcher.  A derivative of the project provides the Django web framework's "signal" system.

To be more concrete about what PyDispatcher does for you:

  • provides a centralized service for delivering messages to registered objects (in the local process).  It allows you to register any number of functions (callable objects) which can receive signals from senders.
    • registration can be for all senders, particular sending objects, or "anonymous" messages (messages where the sender is None)
    • registration can be for any signal, or particular signals
    • a single signal will be delivered to all appropriate registered receivers, so that multiple registrations do not interfere with each other
  • there is no requirement for the sender or receiver to be dispatcher-aware.  Any Python object save the None object can act as a sender, and any callable object can act as a receiver.  There is no need to inherit from a particular class or provide a particular interface on the object.
  • the system uses weak references to receivers wherever possible
    • object lifetimes are not affected by PyDispatcher registrations (that is, when your object goes away, the registrations related to the object also go away). 
    • references to common transient objects (in particular instance methods) are stored as compound weak references. 
    • weak references can be disabled on a registration-by-registration basis
  • allows rich signal types, signals are simply hashable objects used to store and retrieve sub-tables, they are otherwise opaque to the dispatcher mechanism
  • allows sending more information when sending than any particular receiver can handle, dispatcher automatically culls those arguments which are not appropriate for the particular receiver.  This allows registering very simple functions dealing with general messages, while still allowing natural passing of arguments to higher level functions.

The dispatcher mechanism is particularly useful when constructing Model-View-Controller style applications where it is not desirable to have the Model objects aware of the event model.

Acquisition and Installation

PyDispatcher is available as a standard Python distutils installation package from the Python Package Index (PyPI).  To install, run:

pip install PyDispatcher

PyDispatcher does not include any binary packages, so there should be no issues in installation.  PyDispatcher is maintained on the LaunchPad project in bzr.  To help develop, check out the project like so:

bzr branch lp:~mcfletch/pydispatcher/working

You can either send a pull request via LaunchPad or email a patch-set via:

bzr send --mail-to=mcfletch@vrplumber.com

PyDispatcher represents one of the more involved usage patterns for Python weakref objects. We have discovered a few problems in weakref operation of which users of the package should be aware.

Python 2.2.2 (and earlier) weak reference implementations have a subtle bug in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown.  If you are using Python 2.2, it is strongly recommended that you use Python 2.2.3 or later when using PyDispatcher.  Note that this will not address the following issue.

Python 2.3.2 (and earlier) has a different (even more subtle) bug in the weakref destructor code which, again, can cause segfaults.  If you are using Python 2.3, it is strongly recommended that you use Python 2.3.3 or later when using PyDispatcher.  This bug-fix will not be ported back to the Python 2.2.x branch, so if you are using Python 2.2.3 you may encounter this situation.

Documentation

You can find usage samples in the examples directory of the distribution.  The dispatcher module's reference documentation is currently the major source of information regarding usage.

PyDispatcher welcomes contributions, suggestions, and feedback from users in the pydispatcher-dev mailing list.

Usage

To set up a function to receive signals:

from pydispatch import dispatcher
SIGNAL = 'my-first-signal'

def handle_event( sender ):
"""Simple event handler"""
print 'Signal was sent by', sender
dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any )

The use of the Any object allows the handler to listen for messages from any Sender or to listen to Any message being sent.  To send messages:

first_sender = object()
second_sender = {}
def main( ):
dispatcher.send( signal=SIGNAL, sender=first_sender )
dispatcher.send( signal=SIGNAL, sender=second_sender )

Which causes the following to be printed:

Signal was sent by <object object at 0x196a090>
Signal was sent by {}

Handler Functions

Handler functions in PyDispatcher are relatively loose in their definition.  A handler can simply declare the parameters it would like to receive and receive only those parameters when the signal is sent.  The sender can include extra parameters for those handlers which require them without worrying about whether a more generic handler can accept them:

def handle_specific_event( sender, moo ):
"""Handle a simple event, requiring a "moo" parameter"""
print 'Specialized event for %(sender)s moo=%(moo)r'%locals()
dispatcher.connect( handle_specific_event, signal=SIGNAL2, sender=dispatcher.Any )

This connection requires that all senders of the particular signal send a "moo" parameter, but a handler that listens for all events and does not provide a "moo" parameter would silently ignore the sender having passed a "moo".

2 parameters are always available to handler functions if they would like to use them:

Parameter
Value
sender
Object from/for which the event was sent, can be dispatcher.Anonymous for anonymous signals
signal
Signal object used when sending

Positional arguments and named arguments are passed through, but if positional arguments are used, they will fill in the parameters of the receiver in order and cause conflicts if named parameters are specified which match their names.  Generally it is advisable to use named arguments when defining sending messages.

Real World Examples

OpenGLContext uses PyDispatcher to provide a link between PyVRML97 (model level) and OpenGLContext (the controller and view levels).  Changes to fields in the model send events, as do changes to object lists.  A cache observes these changes and allows the view/model level to register dependencies on particular fields of particular nodes.  The result is that rendering code can cache data extensively and have the caches consistently invalidated when their data-dependencies are changed.

Related Software

  • Louie
    • Reworked pydispatcher providing plugin infrastructure including Twisted and PyQt specific support
  • django.dispatch (Signals)
    • Rewritten with a more limited interface, but higher performance; requires that signals be objects of a given type, and eliminates Any registrations.  Registrations are on the signal objects.

Release Notes

  • Version 2.0.5
    • Python 3.x support via shared code-base (not 2to3). Python 2.x is still the primary development target
  • Version 2.0.3
    • Support for Python 3.2 (via 2to3) added, Python 2.x is still the primary development target
  • Version 2.0.2
    • Further packaging fixes.
  • Version 2.0.1 (this version and all previous versions are available from the old SourceForge project)
    • Packaging fixes to allow for easy_install based installation
  • Version 2.0.0
    • Renames the top-level package to "pydispatch" to avoid conflicts with common conflicting "dispatch" module.
  • Version 1.0.3
    • Add "robust" module with single function sendRobust, which catches errors during callbacks and returns the error instances instead of propagating the error
    • Patch bug in SafeRef deletion where traceback module has already been deleted by interpreter shutdown
    • Patch bug in _removeReceiver where sendersBack has already been deleted by interpreter shutdown
    • Make SafeRef pre-cache method name to allow for repr after cleanup of the method
  • Version 1.0.2
    • Fixes another memory leak, again wrt the back-reference table
  • Version 1.0.1
    • Fixes 2 memory leaks, one regarding the back-reference table for receivers, the other being a failure to register all receivers beyond the first for deletion
  • Version 1.0.0
    • Initial SourceForge release with restructured codebase
PyDispatcher-2.0.5/docs/images/0000755000175000001440000000000012455637705017274 5ustar mcfletchusers00000000000000PyDispatcher-2.0.5/docs/images/greypinstripe.png0000644000175000001440000000021312451340306022662 0ustar mcfletchusers00000000000000PNG  IHDR'gAMA@ cHRMntFdIX*LIDATxbb&ښ<IENDB`PyDispatcher-2.0.5/setup.py0000644000175000001440000000515112455637152016607 0ustar mcfletchusers00000000000000#!/usr/bin/env python """Installs PyDispatcher using distutils (or setuptools/distribute) Run: python setup.py install to install the package from the source archive. """ import sys, os try: from setuptools import setup except ImportError: from distutils.core import setup extra_commands = {} extra_arguments = { 'classifiers': [ """License :: OSI Approved :: BSD License""", """Programming Language :: Python""", """Programming Language :: Python :: 3""", """Topic :: Software Development :: Libraries :: Python Modules""", """Intended Audience :: Developers""", ], #'download_url': "http://sourceforge.net/projects/pydispatcher/files/pydispatcher/", 'keywords': 'dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply', 'long_description' : """Dispatcher mechanism for creating event models PyDispatcher is an enhanced version of Patrick K. O'Brien's original dispatcher.py module. It provides the Python programmer with a robust mechanism for event routing within various application contexts. Included in the package are the robustapply and saferef modules, which provide the ability to selectively apply arguments to callable objects and to reference instance methods using weak-references. """, 'platforms': ['Any'], } version = [ (line.split('=')[1]).strip().strip('"').strip("'") for line in open(os.path.join('pydispatch','__init__.py')) if line.startswith( '__version__' ) ][0] if __name__ == "__main__": ### Now the actual set up call setup ( name = "PyDispatcher", version = version, description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", maintainer = "Mike C. Fletcher", author_email = "pydispatcher-devel@lists.sourceforge.net", maintainer_email = "pydispatcher-devel@lists.sourceforge.net", url = "http://pydispatcher.sourceforge.net", license = "BSD", package_dir = { 'pydispatch':'pydispatch', }, packages = [ 'pydispatch', ], options = { 'sdist':{'use_defaults':0, 'force_manifest':1,'formats': ['gztar','zip'],}, 'bdist_rpm':{ 'group':'Libraries/Python', 'provides':'python-dispatcher', 'requires':"python", }, }, cmdclass = extra_commands, # use_2to3 = True, # registration metadata **extra_arguments ) PyDispatcher-2.0.5/PKG-INFO0000644000175000001440000000231412455637705016174 0ustar mcfletchusers00000000000000Metadata-Version: 1.1 Name: PyDispatcher Version: 2.0.5 Summary: Multi-producer-multi-consumer signal dispatching mechanism Home-page: http://pydispatcher.sourceforge.net Author: Mike C. Fletcher Author-email: pydispatcher-devel@lists.sourceforge.net License: BSD Description: Dispatcher mechanism for creating event models PyDispatcher is an enhanced version of Patrick K. O'Brien's original dispatcher.py module. It provides the Python programmer with a robust mechanism for event routing within various application contexts. Included in the package are the robustapply and saferef modules, which provide the ability to selectively apply arguments to callable objects and to reference instance methods using weak-references. Keywords: dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply Platform: Any Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Intended Audience :: Developers