You can subscribe to this list here.
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(24) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2004 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
(1) |
Jun
(4) |
Jul
|
Aug
|
Sep
(1) |
Oct
(3) |
Nov
(3) |
Dec
|
2005 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(5) |
Oct
|
Nov
|
Dec
(1) |
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(2) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(4) |
Dec
|
2010 |
Jan
|
Feb
|
Mar
(8) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:52:27
|
Update of /cvsroot/pydispatcher/pydispatch/docs In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv31545/docs Modified Files: index.html Log Message: Note the release changes Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/docs/index.html,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** index.html 14 Nov 2008 18:09:51 -0000 1.3 --- index.html 30 Mar 2010 15:52:19 -0000 1.4 *************** *** 1,20 **** <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html> ! <head> ! <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> ! <title>Python Dispatch Package</title> <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"> ! </head> ! ! ! <body> <h1>PyDispatcher</h1> --- 1,17 ---- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html><head> ! ! ! <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Python Dispatch Package</title> ! <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"></head><body> <h1>PyDispatcher</h1> *************** *** 192,196 **** --- 189,199 ---- <ul> + <li>Version 2.0.2</li> + <ul> + <li>Further packaging fixes.<br> + </li> + </ul> <li>Version 2.0.1</li> + <ul> <li>Packaging fixes to allow for easy_install based installation</li> *************** *** 268,271 **** <p class="footer">A SourceForge Open-Source project: <a href="http://sourceforge.net"><img title="" alt="SourceForge" style="border: 0px solid ; width: 88px; height: 31px;" src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" align="middle" border="0" height="31" width="88"></a></p> ! </body> ! </html> --- 271,273 ---- <p class="footer">A SourceForge Open-Source project: <a href="http://sourceforge.net"><img title="" alt="SourceForge" style="border: 0px solid ; width: 88px; height: 31px;" src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" align="middle" border="0" height="31" width="88"></a></p> ! </body></html> \ No newline at end of file |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:51:02
|
Update of /cvsroot/pydispatcher/pydispatch/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv31339/pydispatch Modified Files: __init__.py Log Message: Bump version, as 2.0.1 was already released! Index: __init__.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/pydispatch/__init__.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** __init__.py 30 Mar 2010 15:45:55 -0000 1.1 --- __init__.py 30 Mar 2010 15:50:52 -0000 1.2 *************** *** 1,5 **** """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "2.0.1" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" --- 1,5 ---- """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "2.0.2" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:47:32
|
Update of /cvsroot/pydispatcher/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv30414 Removed Files: __init__.py dispatcher.py errors.py robust.py robustapply.py saferef.py Log Message: Remove the files from the root directory --- robustapply.py DELETED --- --- dispatcher.py DELETED --- --- errors.py DELETED --- --- robust.py DELETED --- --- __init__.py DELETED --- --- saferef.py DELETED --- |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:46:03
|
Update of /cvsroot/pydispatcher/pydispatch/tests In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv29940/tests Modified Files: test_saferef.py Removed Files: test.py Log Message: Move to a more standard package layout with sub-package of the code to install. Make tests compatible with nosetest discovery. Make tests *not* install by default. Index: test_saferef.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/tests/test_saferef.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** test_saferef.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- test_saferef.py 30 Mar 2010 15:45:55 -0000 1.2 *************** *** 2,11 **** import unittest ! class Test1( object): def x( self ): pass ! def test2(obj): pass ! class Test2( object ): def __call__( self, obj ): pass --- 2,11 ---- import unittest ! class T1( object): def x( self ): pass ! def t2(obj): pass ! class T2( object ): def __call__( self, obj ): pass *************** *** 15,26 **** ss = [] for x in xrange( 5000 ): ! t = Test1() ts.append( t) s = safeRef(t.x, self._closure ) ss.append( s) ! ts.append( test2 ) ! ss.append( safeRef(test2, self._closure) ) for x in xrange( 30 ): ! t = Test2() ts.append( t) s = safeRef(t, self._closure ) --- 15,26 ---- ss = [] for x in xrange( 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 xrange( 30 ): ! t = T2() ts.append( t) s = safeRef(t, self._closure ) *************** *** 57,61 **** """ repr( self.ss[-1] ) ! def test(self): self.closureCount = 0 --- 57,61 ---- """ repr( self.ss[-1] ) ! def test(self): self.closureCount = 0 *************** *** 65,69 **** 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""" --- 65,69 ---- 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""" --- test.py DELETED --- |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:46:03
|
Update of /cvsroot/pydispatcher/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv29940 Modified Files: setup.py Log Message: Move to a more standard package layout with sub-package of the code to install. Make tests compatible with nosetest discovery. Make tests *not* install by default. Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/setup.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** setup.py 30 Mar 2010 15:32:09 -0000 1.3 --- setup.py 30 Mar 2010 15:45:55 -0000 1.4 *************** *** 3,23 **** Run: ! python setup.py install to install the package from the source archive. """ from setuptools import setup from sys import hexversion if hexversion >= 0x2030000: ! # work around distutils complaints under Python 2.2.x ! extraArguments = { ! 'classifiers': [ ! """License :: OSI Approved :: BSD License""", ! """Programming Language :: Python""", ! """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 --- 3,24 ---- Run: ! python setup.py install to install the package from the source archive. """ from setuptools import setup + import os from sys import hexversion if hexversion >= 0x2030000: ! # work around distutils complaints under Python 2.2.x ! extraArguments = { ! 'classifiers': [ ! """License :: OSI Approved :: BSD License""", ! """Programming Language :: Python""", ! """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 *************** *** 31,71 **** methods using weak-references. """, ! 'platforms': ['Any'], ! } else: ! extraArguments = { ! } if __name__ == "__main__": ! ### Now the actual set up call ! setup ( ! name = "PyDispatcher", ! version = "2.0.1", ! description= "Multi-producer-multi-consumer signal dispatching mechanism", ! author = "Patrick K. O'Brien", ! author_email = "pyd...@li...", ! url = "http://pydispatcher.sourceforge.net", ! license = "BSD-style, see license.txt for details", ! package_dir = { ! 'pydispatch':'.', ! }, ! packages = [ ! 'pydispatch', ! ], ! ! options = { ! 'sdist':{'use_defaults':0, 'force_manifest':1}, ! "install_lib":{"compile":0, "optimize":0}, ! 'bdist_rpm':{ ! 'group':'Libraries/Python', ! 'provides':'python-dispatcher', ! 'requires':"python", ! }, ! }, - # registration metadata - **extraArguments - ) - --- 32,79 ---- methods using weak-references. """, ! 'platforms': ['Any'], ! } else: ! extraArguments = { ! } ! ! ! 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", ! author_email = "pyd...@li...", ! url = "http://pydispatcher.sourceforge.net", ! license = "BSD-style, see license.txt for details", ! package_dir = { ! 'pydispatch':'pydispatch', ! }, ! packages = [ ! 'pydispatch', ! ], ! ! options = { ! 'sdist':{'use_defaults':0, 'force_manifest':1}, ! "install_lib":{"compile":0, "optimize":0}, ! 'bdist_rpm':{ ! 'group':'Libraries/Python', ! 'provides':'python-dispatcher', ! 'requires':"python", ! }, ! }, ! ! # registration metadata ! **extraArguments ! ) |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:46:03
|
Update of /cvsroot/pydispatcher/pydispatch/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv29940/pydispatch Added Files: __init__.py dispatcher.py errors.py robust.py robustapply.py saferef.py Log Message: Move to a more standard package layout with sub-package of the code to install. Make tests compatible with nosetest discovery. Make tests *not* install by default. --- NEW FILE: 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. """ 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__'): # receiver is a class instance; assume it is callable. # 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, receiver.im_func.func_code, 1 elif not hasattr( receiver, 'func_code'): raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) return receiver, 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. for arg in named.keys(): if arg not in acceptable: del named[arg] return receiver(*arguments, **named) --- NEW FILE: 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.) """ from __future__ import generators import types, weakref from pydispatch import saferef, robustapply, errors __author__ = "Patrick K. O'Brien <po...@or...>" __cvsid__ = "$Id: dispatcher.py,v 1.1 2010/03/30 15:45:55 mcfletch Exp $" __version__ = "$Revision: 1.1 $"[11:-2] 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, err: return False else: for senderkey in backSet: try: signals = connections[senderkey].keys() except KeyError,err: pass else: for signal in signals: try: receivers = connections[senderkey][signal] except KeyError: pass else: try: receivers.remove( receiver ) except Exception, err: 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,{}).iteritems(): 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 --- NEW FILE: errors.py --- """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)""" --- NEW FILE: robust.py --- """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, err: responses.append((receiver, err)) else: responses.append((receiver, response)) return responses --- NEW FILE: __init__.py --- """Multi-consumer multi-producer dispatching mechanism """ __version__ = "2.0.1" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" --- NEW FILE: saferef.py --- """Refactored "safe reference" from dispatcher.py""" import weakref, traceback 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 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 im_self, but no im_func, don't know how to create reference"""%( target,) 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 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. """ 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, e: try: traceback.print_exc() except AttributeError, err: print '''Exception during saferef %s cleanup function %s: %s'''%( self, function, e ) self.deletionMethods = [onDelete] self.key = self.calculateKey( target ) self.weakSelf = weakref.ref(target.im_self, remove) self.weakFunc = weakref.ref(target.im_func, remove) self.selfName = target.im_self.__class__.__name__ self.funcName = str(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(target.im_self),id(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 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 |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:34:44
|
Update of /cvsroot/pydispatcher/pydispatch/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv27605/pydispatch Log Message: Directory /cvsroot/pydispatcher/pydispatch/pydispatch added to the repository |
From: Mike C. F. <mcf...@us...> - 2010-03-30 15:32:17
|
Update of /cvsroot/pydispatcher/pydispatch In directory sfp-cvsdas-2.v30.ch3.sourceforge.com:/tmp/cvs-serv26717 Modified Files: __init__.py dispatcher.py robustapply.py saferef.py setup.py Log Message: Eliminate -3 warnings (i.e. prepare for Python 3.x) Bump version. Remove SF download link that's currently broken. Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/setup.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** setup.py 14 Nov 2008 18:09:51 -0000 1.2 --- setup.py 30 Mar 2010 15:32:09 -0000 1.3 *************** *** 17,21 **** """Intended Audience :: Developers""", ], ! 'download_url': "https://sourceforge.net/project/showfiles.php?group_id=79755", 'keywords': 'dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply', 'long_description' : """Dispatcher mechanism for creating event models --- 17,21 ---- """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 Index: dispatcher.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/dispatcher.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** dispatcher.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- dispatcher.py 30 Mar 2010 15:32:09 -0000 1.2 *************** *** 34,43 **** __version__ = "$Revision$"[11:-2] - try: - True - except NameError: - True = 1==1 - False = 1==0 - class _Parameter: """Used to represent default parameter values.""" --- 34,37 ---- *************** *** 141,145 **** receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) senderkey = id(sender) ! if connections.has_key(senderkey): signals = connections[senderkey] else: --- 135,139 ---- receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) senderkey = id(sender) ! if senderkey in connections: signals = connections[senderkey] else: *************** *** 161,165 **** # get current set, remove any current references to # this receiver in the set, including back-references ! if signals.has_key(signal): receivers = signals[signal] _removeOldBackRefs(senderkey, signal, receiver, receivers) --- 155,159 ---- # 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) *************** *** 297,301 **** if receiver: # filter out dead instance-method weakrefs try: ! if not receivers.has_key( receiver ): receivers[receiver] = 1 yield receiver --- 291,295 ---- if receiver: # filter out dead instance-method weakrefs try: ! if receiver not in receivers: receivers[receiver] = 1 yield receiver *************** *** 378,403 **** return False backKey = id(receiver) ! for senderkey in sendersBack.get(backKey,()): ! try: ! signals = connections[senderkey].keys() ! except KeyError,err: ! pass ! else: ! for signal in signals: ! try: ! receivers = connections[senderkey][signal] ! except KeyError: ! pass ! else: try: ! receivers.remove( receiver ) ! except Exception, err: pass ! _cleanupConnections(senderkey, signal) ! try: ! del sendersBack[ backKey ] ! except KeyError: ! pass ! def _cleanupConnections(senderkey, signal): """Delete any empty signals for senderkey. Delete senderkey if empty.""" --- 372,398 ---- return False backKey = id(receiver) ! try: ! backSet = sendersBack.pop(backKey) ! except KeyError, err: ! return False ! else: ! for senderkey in backSet: ! try: ! signals = connections[senderkey].keys() ! except KeyError,err: ! pass ! else: ! for signal in signals: try: ! receivers = connections[senderkey][signal] ! except KeyError: pass ! else: ! try: ! receivers.remove( receiver ) ! except Exception, err: ! pass ! _cleanupConnections(senderkey, signal) ! def _cleanupConnections(senderkey, signal): """Delete any empty signals for senderkey. Delete senderkey if empty.""" Index: robustapply.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/robustapply.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** robustapply.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- robustapply.py 30 Mar 2010 15:32:09 -0000 1.2 *************** *** 33,37 **** acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: ! if named.has_key( name ): raise TypeError( """Argument %r specified both positionally and as a keyword for calling %r"""% ( --- 33,37 ---- 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"""% ( *************** *** 47,49 **** return receiver(*arguments, **named) ! \ No newline at end of file --- 47,49 ---- return receiver(*arguments, **named) ! Index: __init__.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/__init__.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** __init__.py 7 Jul 2006 16:03:59 -0000 1.2 --- __init__.py 30 Mar 2010 15:32:09 -0000 1.3 *************** *** 1,5 **** """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "2.0.0" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" --- 1,5 ---- """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "2.0.1" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" Index: saferef.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/saferef.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** saferef.py 14 Nov 2008 18:08:50 -0000 1.2 --- saferef.py 30 Mar 2010 15:32:09 -0000 1.3 *************** *** 23,27 **** ) return reference ! if callable(onDelete): return weakref.ref(target, onDelete) else: --- 23,27 ---- ) return reference ! if onDelete is not None: return weakref.ref(target, onDelete) else: *************** *** 108,112 **** for function in methods: try: ! if callable( function ): function( self ) except Exception, e: --- 108,112 ---- for function in methods: try: ! if hasattr(function, '__call__' ): function( self ) except Exception, e: |
From: Mike C. F. <mcf...@us...> - 2008-11-14 18:09:57
|
Update of /cvsroot/pydispatcher/pydispatch In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv25823 Modified Files: pydispatcher-1.0.0.ebuild setup.py Removed Files: pydispatch.e3p Log Message: Bump to version 2.0.1, packaging fixes for setuptools. Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/setup.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** setup.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- setup.py 14 Nov 2008 18:09:51 -0000 1.2 *************** *** 6,69 **** to install the package from the source archive. """ ! ! if __name__ == "__main__": ! import sys,os, string, fnmatch ! from distutils.sysconfig import * ! from distutils.core import setup ! ! ############## ! ## Following is from Pete Shinners, ! ## apparently it will work around the reported bug on ! ## some unix machines where the data files are copied ! ## to weird locations if the user's configuration options ! ## were entered during the wrong phase of the moon :) . ! from distutils.command.install_data import install_data ! class smart_install_data(install_data): ! def run(self): ! #need to change self.install_dir to the library dir ! install_cmd = self.get_finalized_command('install') ! self.install_dir = getattr(install_cmd, 'install_lib') ! # should create the directory if it doesn't exist!!! ! return install_data.run(self) ! ############## ! ### The following automates the inclusion of files while avoiding problems with UNIX ! ### where case sensitivity matters. ! dataFiles = [] ! excludedTypes = ('.py','.pyc','.pyo','.db','.gz','.bat', ".cvsignore") ! excludedDirectories = ('build','dist','cvs') ! def nonPythonFile( file ): ! """Is the fully-qualified name a non-python file""" ! if os.path.isfile( file ): ! return (os.path.splitext( file )[1]).lower() not in excludedTypes ! def directoryWalker( argument, directory, files, prefix = "pydispatch"): ! """Walk the particular directory searching for non-python files ! ! prefix -- prefix directory appended to the destination ! directories, normally the name of the target package ! """ ! if os.path.split(directory.lower())[-1] in excludedDirectories: ! return ! result = [] ! for file in files: ! file = os.path.join(directory,file ) ! if nonPythonFile( file ): ! result.append( file ) ! if result: ! argument.append((os.path.join(prefix,directory), result)) ! os.path.walk( '.', directoryWalker, dataFiles) ! ! from sys import hexversion ! if hexversion >= 0x2030000: ! # work around distutils complaints under Python 2.2.x ! extraArguments = { ! 'classifiers': [ ! """License :: OSI Approved :: BSD License""", ! """Programming Language :: Python""", ! """Topic :: Software Development :: Libraries :: Python Modules""", ! """Intended Audience :: Developers""", ! ], ! 'download_url': "https://sourceforge.net/project/showfiles.php?group_id=79755", ! '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 --- 6,23 ---- to install the package from the source archive. """ ! from setuptools import setup ! from sys import hexversion ! if hexversion >= 0x2030000: ! # work around distutils complaints under Python 2.2.x ! extraArguments = { ! 'classifiers': [ ! """License :: OSI Approved :: BSD License""", ! """Programming Language :: Python""", ! """Topic :: Software Development :: Libraries :: Python Modules""", ! """Intended Audience :: Developers""", ! ], ! 'download_url': "https://sourceforge.net/project/showfiles.php?group_id=79755", ! '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 *************** *** 77,90 **** methods using weak-references. """, ! 'platforms': ['Any'], ! } ! else: ! extraArguments = { ! } ### Now the actual set up call setup ( name = "PyDispatcher", ! version = "2.0.0", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", --- 31,45 ---- methods using weak-references. """, ! 'platforms': ['Any'], ! } ! else: ! extraArguments = { ! } + if __name__ == "__main__": ### Now the actual set up call setup ( name = "PyDispatcher", ! version = "2.0.1", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", *************** *** 99,104 **** packages = [ 'pydispatch', - 'pydispatch.tests', - 'pydispatch.examples', ], --- 54,57 ---- *************** *** 112,117 **** }, }, - data_files = dataFiles, - cmdclass = {'install_data':smart_install_data}, # registration metadata --- 65,68 ---- --- pydispatch.e3p DELETED --- |
From: Mike C. F. <mcf...@us...> - 2008-11-14 18:09:56
|
Update of /cvsroot/pydispatcher/pydispatch/docs In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv25823/docs Modified Files: index.html Log Message: Bump to version 2.0.1, packaging fixes for setuptools. Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/docs/index.html,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** index.html 7 Jul 2006 16:03:59 -0000 1.2 --- index.html 14 Nov 2008 18:09:51 -0000 1.3 *************** *** 2,42 **** <html> <head> ! <meta content="text/html; charset=ISO-8859-1" ! http-equiv="content-type"> <title>Python Dispatch Package</title> <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> <meta content="Patrick K. O'Brien" name="author"> </head> <body> <h1>PyDispatcher</h1> <p class="introduction">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 <a ! href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a ! href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> </p> <p>To be more concrete about what PyDispatcher does for you:<br> </p> <ul> <li>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.</li> <ul> <li>registration can be for all senders, particular sending objects, or "anonymous" messages (messages where the sender is None)<br> </li> <li>registration can be for any signal, or particular signals</li> <li>a single signal will be delivered to all appropriate registered receivers, so that multiple registrations do not interfere with each other<br> </li> </ul> <li>there is no requirement for the sender or receiver to be dispatcher-aware. Any Python object save the None object can act --- 2,65 ---- <html> <head> ! ! ! <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"> ! ! ! <title>Python Dispatch Package</title> <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> + + <meta content="Patrick K. O'Brien" name="author"> </head> + + <body> + <h1>PyDispatcher</h1> + <p class="introduction">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 <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> + </p> + <p>To be more concrete about what PyDispatcher does for you:<br> + </p> + <ul> + <li>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.</li> + + <ul> + <li>registration can be for all senders, particular sending objects, or "anonymous" messages (messages where the sender is None)<br> + </li> + <li>registration can be for any signal, or particular signals</li> + <li>a single signal will be delivered to all appropriate registered receivers, so that multiple registrations do not interfere with each other<br> + </li> + + </ul> + <li>there is no requirement for the sender or receiver to be dispatcher-aware. Any Python object save the None object can act *************** *** 44,63 **** --- 67,99 ---- is no need to inherit from a particular class or provide a particular interface on the object.<br> + </li> + <li>the system uses weak references to receivers wherever possible</li> + + <ul> + <li>object lifetimes are not affected by PyDispatcher registrations (that is, when your object goes away, the registrations related to the object also go away). <br> + </li> + <li>references to common transient objects (in particular instance methods) are stored as compound weak references. <br> + </li> + <li>weak references can be disabled on a registration-by-registration basis</li> + + </ul> + <li>allows rich signal types, signals are simply hashable objects used to store and retrieve sub-tables, they are otherwise opaque to the dispatcher mechanism</li> + <li>allows sending more information when sending than any particular receiver can handle, dispatcher automatically culls those arguments *************** *** 66,96 **** while still allowing natural passing of arguments to higher level functions.<br> </li> </ul> <p>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.</p> <h2>Acquisition and Installation</h2> <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a ! href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> </p> <pre>python setup.py install<br></pre> <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a ! href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> </p> <p class="technical">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.<br> </p> <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a ! href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, --- 102,141 ---- while still allowing natural passing of arguments to higher level functions.<br> + </li> + </ul> + <p>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.</p> + <h2>Acquisition and Installation</h2> + <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> + </p> + <pre>python setup.py install<br></pre> + <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> + </p> + <p class="technical">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.<br> + </p> + <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, *************** *** 100,107 **** when using PyDispatcher. Note that this will not address the following issue.<br> </p> <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a ! href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly --- 145,153 ---- when using PyDispatcher. Note that this will not address the following issue.<br> + </p> + <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly *************** *** 112,174 **** encounter this situation. </p> <h2>Documentation</h2> <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a ! href="pydoc/pydispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a ! href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.</p> <h2>Related Software</h2> <ul> <li><a href="http://louie.berlios.de/">Louie</a></li> <ul> <li>Reworked pydispatcher providing plugin infrastructure including Twisted and PyQt specific support</li> </ul> </ul> <h2>Release Notes</h2> <ul> <li>Version 2.0.0</li> <ul> <li>Renames the top-level package to "pydispatch" to avoid conflicts with common conflicting "dispatch" module.</li> </ul> <li>Version 1.0.3</li> <ul> <li>Add "robust" module with single function sendRobust, which catches errors during callbacks and returns the error instances instead of propagating the error</li> <li>Patch bug in SafeRef deletion where traceback module has already been deleted by interpreter shutdown</li> <li>Patch bug in _removeReceiver where sendersBack has already been deleted by interpreter shutdown</li> <li>Make SafeRef pre-cache method name to allow for repr after cleanup of the method</li> </ul> <li>Version 1.0.2</li> <ul> <li>Fixes another memory leak, again wrt the back-reference table<br> </li> </ul> <li>Version 1.0.1</li> <ul> <li>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</li> </ul> <li>Version 1.0.0</li> <ul> <li>Initial SourceForge release with restructured codebase<br> </li> </ul> </ul> ! <p class="footer">A SourceForge Open-Source project: <a ! href="http://sourceforge.net"><img title="" alt="SourceForge" ! style="border: 0px solid ; width: 88px; height: 31px;" ! src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" ! align="middle" border="0" height="31" width="88"></a></p> </body> </html> --- 158,271 ---- encounter this situation. </p> + <h2>Documentation</h2> + <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a href="pydoc/pydispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> + </p> + <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.</p> + <h2>Related Software</h2> + <ul> + <li><a href="http://louie.berlios.de/">Louie</a></li> + + <ul> + <li>Reworked pydispatcher providing plugin infrastructure including Twisted and PyQt specific support</li> + + </ul> + </ul> + <h2>Release Notes</h2> + <ul> + + <li>Version 2.0.1</li> + <ul> + <li>Packaging fixes to allow for easy_install based installation</li> + </ul> <li>Version 2.0.0</li> + + <ul> + <li>Renames the top-level package to "pydispatch" to avoid conflicts with common conflicting "dispatch" module.</li> + + </ul> + <li>Version 1.0.3</li> + + <ul> + <li>Add "robust" module with single function sendRobust, which catches errors during callbacks and returns the error instances instead of propagating the error</li> + <li>Patch bug in SafeRef deletion where traceback module has already been deleted by interpreter shutdown</li> + <li>Patch bug in _removeReceiver where sendersBack has already been deleted by interpreter shutdown</li> + <li>Make SafeRef pre-cache method name to allow for repr after cleanup of the method</li> + + </ul> + <li>Version 1.0.2</li> + + <ul> + <li>Fixes another memory leak, again wrt the back-reference table<br> + </li> + + </ul> + <li>Version 1.0.1</li> + + <ul> + <li>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</li> + + </ul> + <li>Version 1.0.0</li> + + <ul> + <li>Initial SourceForge release with restructured codebase<br> + </li> + + </ul> + </ul> ! ! <p class="footer">A SourceForge Open-Source project: <a href="http://sourceforge.net"><img title="" alt="SourceForge" style="border: 0px solid ; width: 88px; height: 31px;" src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" align="middle" border="0" height="31" width="88"></a></p> ! </body> </html> |
From: Mike C. F. <mcf...@us...> - 2008-11-14 18:08:54
|
Update of /cvsroot/pydispatcher/pydispatch In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv25618 Modified Files: saferef.py Log Message: Avoid calling str() on targets, as this can be a non-trivial amount of work e.g. for array objects Index: saferef.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/saferef.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** saferef.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- saferef.py 14 Nov 2008 18:08:50 -0000 1.2 *************** *** 121,125 **** self.weakSelf = weakref.ref(target.im_self, remove) self.weakFunc = weakref.ref(target.im_func, remove) ! self.selfName = str(target.im_self) self.funcName = str(target.im_func.__name__) def calculateKey( cls, target ): --- 121,125 ---- self.weakSelf = weakref.ref(target.im_self, remove) self.weakFunc = weakref.ref(target.im_func, remove) ! self.selfName = target.im_self.__class__.__name__ self.funcName = str(target.im_func.__name__) def calculateKey( cls, target ): |
From: Mike C. F. <mcf...@us...> - 2008-11-14 18:07:57
|
Update of /cvsroot/pydispatcher/pydispatch In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv25499 Modified Files: MANIFEST.in Log Message: Recursive versus regular includes Index: MANIFEST.in =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/MANIFEST.in,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** MANIFEST.in 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- MANIFEST.in 14 Nov 2008 18:07:50 -0000 1.2 *************** *** 2,10 **** include license.txt include *.py ! include docs *.html ! include docs/images *.png ! include docs/style *.css ! include docs/pydoc *.html *.py ! include examples *.py global-exclude *.bat --- 2,12 ---- 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 |
From: Mike C. F. <mcf...@us...> - 2006-07-07 16:04:12
|
Update of /cvsroot/pydispatcher/pydispatch/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22600/docs Modified Files: index.html Log Message: Minor fixes to agree with the new package name Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/docs/index.html,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** index.html 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- index.html 7 Jul 2006 16:03:59 -0000 1.2 *************** *** 115,119 **** <p>You can find usage samples in the examples directory of the distribution. The dispatcher module's <a ! href="pydoc/dispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> --- 115,119 ---- <p>You can find usage samples in the examples directory of the distribution. The dispatcher module's <a ! href="pydoc/pydispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> |
From: Mike C. F. <mcf...@us...> - 2006-07-07 16:04:09
|
Update of /cvsroot/pydispatcher/pydispatch In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22600 Modified Files: __init__.py Log Message: Minor fixes to agree with the new package name Index: __init__.py =================================================================== RCS file: /cvsroot/pydispatcher/pydispatch/__init__.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** __init__.py 7 Jul 2006 15:59:38 -0000 1.1.1.1 --- __init__.py 7 Jul 2006 16:03:59 -0000 1.2 *************** *** 1,5 **** """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "1.0.0" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" --- 1,5 ---- """Multi-consumer multi-producer dispatching mechanism """ ! __version__ = "2.0.0" __author__ = "Patrick K. O'Brien" __license__ = "BSD-style, see license.txt for details" |
From: Mike C. F. <mcf...@us...> - 2005-12-02 08:51:30
|
Update of /cvsroot/pydispatcher/dispatch/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26278/docs Modified Files: index.html Log Message: Add link to Louie Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/docs/index.html,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** index.html 17 Sep 2005 05:37:11 -0000 1.8 --- index.html 2 Dec 2005 08:51:20 -0000 1.9 *************** *** 121,126 **** users in the pydispatcher-dev <a href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing ! list</a>.<br> ! </p> <h2>Release Notes</h2> <ul> --- 121,133 ---- users in the pydispatcher-dev <a href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing ! list</a>.</p> ! <h2>Related Software</h2> ! <ul> ! <li><a href="http://louie.berlios.de/">Louie</a></li> ! <ul> ! <li>Reworked pydispatcher providing plugin infrastructure including ! Twisted and PyQt specific support</li> ! </ul> ! </ul> <h2>Release Notes</h2> <ul> |
From: Mike C. F. <mcf...@us...> - 2005-09-17 05:37:21
|
Update of /cvsroot/pydispatcher/dispatch/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15623/docs Modified Files: index.html Log Message: Urgh, didn't get the index.html changes checked in first time Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/docs/index.html,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** index.html 26 Nov 2004 06:37:33 -0000 1.7 --- index.html 17 Sep 2005 05:37:11 -0000 1.8 *************** *** 1,8 **** <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html><head> ! <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Python Dispatch Package</title> ! <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"></head> <body> <h1>PyDispatcher</h1> --- 1,11 ---- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html> ! <head> ! <meta content="text/html; charset=ISO-8859-1" ! http-equiv="content-type"> ! <title>Python Dispatch Package</title> <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"> ! </head> <body> <h1>PyDispatcher</h1> *************** *** 11,17 **** routing infrastructure for use in multiple contexts. The mechanism ! of PyDispatcher started life as a highly rated <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> --- 14,22 ---- routing infrastructure for use in multiple contexts. The mechanism ! of PyDispatcher started life as a highly rated <a ! href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a ! href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> *************** *** 68,72 **** <h2>Acquisition and Installation</h2> <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> --- 73,78 ---- <h2>Acquisition and Installation</h2> <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a ! href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> *************** *** 74,78 **** <pre>python setup.py install<br></pre> <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> --- 80,85 ---- <pre>python setup.py install<br></pre> <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a ! href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> *************** *** 84,88 **** </p> <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, --- 91,96 ---- </p> <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a ! href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, *************** *** 94,98 **** </p> <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly --- 102,107 ---- </p> <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a ! href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly *************** *** 105,117 **** <h2>Documentation</h2> <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a href="pydoc/dispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.<br> </p> <h2>Release Notes</h2> <ul> <li>Version 1.0.2</li> <ul> --- 114,140 ---- <h2>Documentation</h2> <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a ! href="pydoc/dispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a ! href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.<br> </p> <h2>Release Notes</h2> <ul> + <li>Version 1.0.3</li> + <ul> + <li>Add "robust" module with single function sendRobust, which + catches errors during callbacks and returns the error instances instead + of propagating the error</li> + <li>Patch bug in SafeRef deletion where traceback module has + already been deleted by interpreter shutdown</li> + <li>Patch bug in _removeReceiver where sendersBack has already been + deleted by interpreter shutdown</li> + <li>Make SafeRef pre-cache method name to allow for repr after + cleanup of the method</li> + </ul> <li>Version 1.0.2</li> <ul> *************** *** 120,124 **** </ul> <li>Version 1.0.1</li> - <ul> <li>Fixes 2 memory leaks, one regarding the back-reference table --- 143,146 ---- *************** *** 132,136 **** </ul> </ul> ! ! <p class="footer">A SourceForge Open-Source project: <a href="http://sourceforge.net"><img title="" alt="SourceForge" style="border: 0px solid ; width: 88px; height: 31px;" src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" align="middle" border="0" height="31" width="88"></a></p> ! </body></html> \ No newline at end of file --- 154,162 ---- </ul> </ul> ! <p class="footer">A SourceForge Open-Source project: <a ! href="http://sourceforge.net"><img title="" alt="SourceForge" ! style="border: 0px solid ; width: 88px; height: 31px;" ! src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" ! align="middle" border="0" height="31" width="88"></a></p> ! </body> ! </html> |
From: Mike C. F. <mcf...@us...> - 2005-09-17 05:33:00
|
Update of /cvsroot/pydispatcher/dispatch In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15076 Modified Files: saferef.py setup.py Added Files: robust.py Log Message: 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 Make SafeRef pre-cache method name to allow for repr after cleanup of the method Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/setup.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** setup.py 26 Nov 2004 06:37:33 -0000 1.6 --- setup.py 17 Sep 2005 05:32:53 -0000 1.7 *************** *** 86,90 **** setup ( name = "PyDispatcher", ! version = "1.0.2", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", --- 86,90 ---- setup ( name = "PyDispatcher", ! version = "1.0.3", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", --- NEW FILE: robust.py --- """Module implementing error-catching version of send (sendRobust)""" from dispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers from dispatch.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, err: responses.append((receiver, err)) else: responses.append((receiver, response)) return responses Index: saferef.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/saferef.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** saferef.py 1 Jul 2003 03:52:28 -0000 1.1.1.1 --- saferef.py 17 Sep 2005 05:32:53 -0000 1.2 *************** *** 59,63 **** to the same (object, function) pair produce the same BoundMethodWeakref instance. ! """ _allInstances = weakref.WeakValueDictionary() --- 59,63 ---- to the same (object, function) pair produce the same BoundMethodWeakref instance. ! """ _allInstances = weakref.WeakValueDictionary() *************** *** 110,119 **** if callable( function ): function( self ) ! except Exception: ! traceback.print_exc() self.deletionMethods = [onDelete] self.key = self.calculateKey( target ) self.weakSelf = weakref.ref(target.im_self, remove) self.weakFunc = weakref.ref(target.im_func, remove) def calculateKey( cls, target ): """Calculate the reference key for this reference --- 110,126 ---- if callable( function ): function( self ) ! except Exception, e: ! try: ! traceback.print_exc() ! except AttributeError, err: ! print '''Exception during saferef %s cleanup function %s: %s'''%( ! self, function, e ! ) self.deletionMethods = [onDelete] self.key = self.calculateKey( target ) self.weakSelf = weakref.ref(target.im_self, remove) self.weakFunc = weakref.ref(target.im_func, remove) + self.selfName = str(target.im_self) + self.funcName = str(target.im_func.__name__) def calculateKey( cls, target ): """Calculate the reference key for this reference *************** *** 128,133 **** return """%s( %s.%s )"""%( self.__class__.__name__, ! self.weakSelf(), ! self.weakFunc().__name__, ) __repr__ = __str__ --- 135,140 ---- return """%s( %s.%s )"""%( self.__class__.__name__, ! self.selfName, ! self.funcName, ) __repr__ = __str__ |
From: Mike C. F. <mcf...@us...> - 2005-09-17 05:33:00
|
Update of /cvsroot/pydispatcher/dispatch/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15076/tests Modified Files: test_dispatcher.py Log Message: 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 Make SafeRef pre-cache method name to allow for repr after cleanup of the method Index: test_dispatcher.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/tests/test_dispatcher.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** test_dispatcher.py 26 Nov 2004 06:37:33 -0000 1.2 --- test_dispatcher.py 17 Sep 2005 05:32:53 -0000 1.3 *************** *** 1,4 **** from dispatch.dispatcher import * ! from dispatch import dispatcher import unittest, pprint --- 1,4 ---- from dispatch.dispatcher import * ! from dispatch import dispatcher, robust import unittest, pprint *************** *** 112,115 **** --- 112,126 ---- del result self._isclean() + def testRobust( self ): + """Test the sendRobust function""" + def fails( ): + raise ValueError( 'this' ) + a = object() + signal = 'this' + connect( fails, Any, a ) + result = robust.sendRobust('this',a, a=a) + err = result[0][1] + assert isinstance( err, ValueError ) + assert err.args == ('this',) def getSuite(): |
From: Mike C. F. <mcf...@us...> - 2005-09-17 04:56:07
|
Update of /cvsroot/pydispatcher/dispatch In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10600 Modified Files: dispatcher.py Log Message: Fix _removeReceiver to deal with case where Python shutdown has replaced sendersBack with None Index: dispatcher.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/dispatcher.py,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** dispatcher.py 26 Nov 2004 06:37:33 -0000 1.8 --- dispatcher.py 17 Sep 2005 04:55:57 -0000 1.9 *************** *** 35,42 **** try: ! True except NameError: ! True = 1==1 ! False = 1==0 class _Parameter: --- 35,42 ---- try: ! True except NameError: ! True = 1==1 ! False = 1==0 class _Parameter: *************** *** 374,377 **** --- 374,380 ---- 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) for senderkey in sendersBack.get(backKey,()): *************** *** 425,430 **** # Senderkey will only be in senders dictionary if sender # could be weakly referenced. ! try: del senders[senderkey] ! except: pass --- 428,435 ---- # Senderkey will only be in senders dictionary if sender # could be weakly referenced. ! try: ! del senders[senderkey] ! except: ! pass |
From: Mike C. F. <mcf...@us...> - 2005-09-17 04:36:58
|
Update of /cvsroot/pydispatcher/dispatch/examples In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8143/examples Modified Files: simple_sample.py Log Message: Fix the samples print statements to make sense wrt direction of the events Index: simple_sample.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/examples/simple_sample.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** simple_sample.py 6 Jul 2003 22:53:21 -0000 1.2 --- simple_sample.py 17 Sep 2005 04:36:50 -0000 1.3 *************** *** 58,62 **** sender = ourObjects[0], ) ! print "Sending DO_LOTS to first object" dispatcher.send( signal = DO_LOTS, --- 58,62 ---- sender = ourObjects[0], ) ! print "Sending DO_LOTS from first object" dispatcher.send( signal = DO_LOTS, *************** *** 64,68 **** table = "Table Argument", ) ! print "Sending DO_SOMETHING to first object" dispatcher.send( signal = DO_SOMETHING, --- 64,68 ---- table = "Table Argument", ) ! print "Sending DO_SOMETHING from first object" dispatcher.send( signal = DO_SOMETHING, *************** *** 70,74 **** table = "Table Argument", ) ! print "Sending DO_SOMETHING_ELSE to first object" dispatcher.send( signal = DO_SOMETHING_ELSE, --- 70,74 ---- table = "Table Argument", ) ! print "Sending DO_SOMETHING_ELSE from first object" dispatcher.send( signal = DO_SOMETHING_ELSE, |
From: Mike C. F. <mcf...@us...> - 2004-11-26 06:37:46
|
Update of /cvsroot/pydispatcher/dispatch In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1551 Modified Files: dispatcher.py setup.py Log Message: Fixes for some very slow memory leaks showing up in one of our applications. Includes addition to the test suite that asserts that everything has been cleaned up after *every* dispatcher test. This is again a back-reference table leak, hopefully the last one. Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/setup.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** setup.py 18 Oct 2004 04:22:58 -0000 1.5 --- setup.py 26 Nov 2004 06:37:33 -0000 1.6 *************** *** 86,90 **** setup ( name = "PyDispatcher", ! version = "1.0.1", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", --- 86,90 ---- setup ( name = "PyDispatcher", ! version = "1.0.2", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", Index: dispatcher.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/dispatcher.py,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** dispatcher.py 18 Oct 2004 04:09:32 -0000 1.7 --- dispatcher.py 26 Nov 2004 06:37:33 -0000 1.8 *************** *** 157,179 **** except: pass try: - receiverID = id(receiver) current = sendersBack.get( receiverID ) if current is None: sendersBack[ receiverID ] = current = [] ! current.append(senderkey) except: pass ! receivers = [] ! if signals.has_key(signal): ! receivers = signals[signal] ! else: ! signals[signal] = receivers ! try: ! receivers.remove(receiver) ! except ValueError: ! pass receivers.append(receiver) def disconnect(receiver, signal=Any, sender=Any, weak=True): """Disconnect receiver from sender for signal --- 157,182 ---- except: pass + + receiverID = id(receiver) + # get current set, remove any current references to + # this receiver in the set, including back-references + if signals.has_key(signal): + 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 *************** *** 209,213 **** senderkey = id(sender) try: ! receivers = connections[senderkey][signal] except KeyError: raise errors.DispatcherKeyError( --- 212,217 ---- senderkey = id(sender) try: ! signals = connections[senderkey] ! receivers = signals[signal] except KeyError: raise errors.DispatcherKeyError( *************** *** 218,222 **** ) try: ! receivers.remove(receiver) except ValueError: raise errors.DispatcherKeyError( --- 222,227 ---- ) try: ! # also removes from receivers ! _removeOldBackRefs(senderkey, signal, receiver, receivers) except ValueError: raise errors.DispatcherKeyError( *************** *** 268,272 **** else: yield receiver ! def getAllReceivers( sender = Any, signal = Any ): """Get list of all receivers from global tables --- 273,279 ---- else: yield receiver ! ! ! def getAllReceivers( sender = Any, signal = Any ): """Get list of all receivers from global tables *************** *** 411,414 **** --- 418,422 ---- def _removeSender(senderkey): """Remove senderkey from connections.""" + _removeBackrefs(senderkey) try: del connections[senderkey] *************** *** 420,421 **** --- 428,492 ---- 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,{}).iteritems(): + 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 |
From: Mike C. F. <mcf...@us...> - 2004-11-26 06:37:43
|
Update of /cvsroot/pydispatcher/dispatch/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1551/docs Modified Files: index.html Log Message: Fixes for some very slow memory leaks showing up in one of our applications. Includes addition to the test suite that asserts that everything has been cleaned up after *every* dispatcher test. This is again a back-reference table leak, hopefully the last one. Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/docs/index.html,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** index.html 18 Oct 2004 04:22:58 -0000 1.6 --- index.html 26 Nov 2004 06:37:33 -0000 1.7 *************** *** 5,9 **** <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> <meta content="Patrick K. O'Brien" name="author"></head> - <body> <h1>PyDispatcher</h1> --- 5,8 ---- *************** *** 115,119 **** --- 114,124 ---- <h2>Release Notes</h2> <ul> + <li>Version 1.0.2</li> + <ul> + <li>Fixes another memory leak, again wrt the back-reference table<br> + </li> + </ul> <li>Version 1.0.1</li> + <ul> <li>Fixes 2 memory leaks, one regarding the back-reference table |
From: Mike C. F. <mcf...@us...> - 2004-11-26 06:37:43
|
Update of /cvsroot/pydispatcher/dispatch/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1551/tests Modified Files: test_dispatcher.py Log Message: Fixes for some very slow memory leaks showing up in one of our applications. Includes addition to the test suite that asserts that everything has been cleaned up after *every* dispatcher test. This is again a back-reference table leak, hopefully the last one. Index: test_dispatcher.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/tests/test_dispatcher.py,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -C2 -d -r1.1.1.1 -r1.2 *** test_dispatcher.py 1 Jul 2003 03:52:28 -0000 1.1.1.1 --- test_dispatcher.py 26 Nov 2004 06:37:33 -0000 1.2 *************** *** 1,11 **** from dispatch.dispatcher import * ! import unittest def x(a): return a class DispatcherTests(unittest.TestCase): """Test suite for dispatcher (barely started)""" def testExact (self): ! a = object() signal = 'this' connect( x, signal, a ) --- 1,28 ---- from dispatch.dispatcher import * + from dispatch import dispatcher ! import unittest, pprint 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 ) *************** *** 15,29 **** disconnect( x, signal, a ) assert len(list(getAllReceivers(a,signal))) == 0 def testAnonymousSend(self): ! a = object() signal = 'this' connect( x, signal ) expected = [(x,a)] ! result = send('this',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 def testAnyRegistration(self): ! a = object() signal = 'this' connect( x, signal, Any ) --- 32,48 ---- 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 ) *************** *** 36,42 **** assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(Any,signal))) == 0 def testAnyRegistration2(self): ! a = object() signal = 'this' connect( x, Any, a ) --- 55,63 ---- 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 ) *************** *** 46,55 **** disconnect( x, Any, a ) assert len(list(getAllReceivers(a,Any))) == 0 def testGarbageCollected(self): ! class x: ! def a( self, a ): ! return a ! a = x() ! b = object() signal = 'this' connect( a.a, signal, b ) --- 67,74 ---- 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 ) *************** *** 59,68 **** 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),) def testGarbageCollectedObj(self): class x: def __call__( self, a ): return a ! a = x() ! b = object() signal = 'this' connect( a, signal, b ) --- 78,88 ---- 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 ) *************** *** 72,75 **** --- 92,116 ---- 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 getSuite(): return unittest.makeSuite(DispatcherTests,'test') |
From: Mike C. F. <mcf...@us...> - 2004-10-18 04:23:08
|
Update of /cvsroot/pydispatcher/dispatch/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24324/docs Modified Files: index.html Log Message: Release notes and version bump Index: index.html =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/docs/index.html,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** index.html 31 Dec 2003 09:02:54 -0000 1.5 --- index.html 18 Oct 2004 04:22:58 -0000 1.6 *************** *** 1,11 **** <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html> ! <head> ! <meta content="text/html; charset=ISO-8859-1" ! http-equiv="content-type"> ! <title>Python Dispatch Package</title> <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"> ! </head> <body> <h1>PyDispatcher</h1> --- 1,9 ---- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> ! <html><head> ! <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Python Dispatch Package</title> ! <link href="style/sitestyle.css" type="text/css" rel="stylesheet"> ! <meta content="Patrick K. O'Brien" name="author"></head> ! <body> <h1>PyDispatcher</h1> *************** *** 14,22 **** routing infrastructure for use in multiple contexts. The mechanism ! of PyDispatcher started life as a highly rated <a ! href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a ! href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> --- 12,18 ---- routing infrastructure for use in multiple contexts. The mechanism ! of PyDispatcher started life as a highly rated <a href="http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056">recipe</a> in the <a href="http://aspn.activestate.com/ASPN/Python/Cookbook/">Python ! Cookbook</a>. The SourceForge <a href="https://sourceforge.net/projects/pydispatcher/">project</a> aims to include various enhancements to the recipe developed during use in various applications.<br> *************** *** 73,78 **** <h2>Acquisition and Installation</h2> <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a ! href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> --- 69,73 ---- <h2>Acquisition and Installation</h2> <p>PyDispatcher is available as a standard Python distutils ! installation package from the SourceForge project <a href="https://sourceforge.net/project/showfiles.php?group_id=79755">file repository</a>. To install, unzip the source archive into a temporary directory and run:<br> *************** *** 80,85 **** <pre>python setup.py install<br></pre> <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a ! href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> --- 75,79 ---- <pre>python setup.py install<br></pre> <p>PyDispatcher does not include any binary packages, so there should ! be no issues in installation. To use the <a href="https://sourceforge.net/cvs/?group_id=79755">CVS version</a> of PyDispatcher (useful for developers of PyDispatcher), simply check out the module to a directory on your PythonPath.<br> *************** *** 91,96 **** </p> <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a ! href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, --- 85,89 ---- </p> <p class="technical">Python 2.2.2 (and ! earlier) weak reference implementations have a subtle <a href="https://sourceforge.net/tracker/?group_id=5470&atid=105470&func=detail&aid=742911">bug</a> in their weakref destructor code which can cause memory access errors (aka segfaults) on program shutdown. If you are using Python 2.2, *************** *** 102,107 **** </p> <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a ! href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly --- 95,99 ---- </p> <p class="technical">Python 2.3.2 (and earlier) has a different (even ! more subtle) <a href="http://cvs.sourceforge.net/viewcvs.py/python/python/dist/src/Modules/gc_weakref.txt?rev=2.1&view=auto">bug</a> in the weakref destructor code which, again, can cause segfaults. If you are using Python 2.3, it is <strong>strongly *************** *** 114,131 **** <h2>Documentation</h2> <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a ! href="pydoc/dispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a ! href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.<br> </p> ! <p class="footer">A SourceForge Open-Source project: <a ! href="http://sourceforge.net"><img border="0" height="31" width="88" ! align="middle" title="" alt="SourceForge" ! style="border: 0px solid ; width: 88px; height: 31px;" ! src="http://sourceforge.net/sflogo.php?group_id=79755&type=1"></a></p> ! </body> ! </html> --- 106,131 ---- <h2>Documentation</h2> <p>You can find usage samples in the examples directory of the ! distribution. The dispatcher module's <a href="pydoc/dispatch.dispatcher.html">reference documentation</a> is currently the major source of information regarding usage.<br> </p> <p>PyDispatcher welcomes contributions, suggestions, and feedback from ! users in the pydispatcher-dev <a href="http://lists.sourceforge.net/lists/listinfo/pydispatcher-devel">mailing list</a>.<br> </p> ! <h2>Release Notes</h2> ! <ul> ! <li>Version 1.0.1</li> ! <ul> ! <li>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</li> ! </ul> ! <li>Version 1.0.0</li> ! <ul> ! <li>Initial SourceForge release with restructured codebase<br> ! </li> ! </ul> ! </ul> ! ! <p class="footer">A SourceForge Open-Source project: <a href="http://sourceforge.net"><img title="" alt="SourceForge" style="border: 0px solid ; width: 88px; height: 31px;" src="http://sourceforge.net/sflogo.php?group_id=79755&type=1" align="middle" border="0" height="31" width="88"></a></p> ! </body></html> \ No newline at end of file |
From: Mike C. F. <mcf...@us...> - 2004-10-18 04:23:08
|
Update of /cvsroot/pydispatcher/dispatch In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24324 Modified Files: setup.py Log Message: Release notes and version bump Index: setup.py =================================================================== RCS file: /cvsroot/pydispatcher/dispatch/setup.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** setup.py 20 May 2004 05:20:37 -0000 1.4 --- setup.py 18 Oct 2004 04:22:58 -0000 1.5 *************** *** 86,90 **** setup ( name = "PyDispatcher", ! version = "1.0.0", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", --- 86,90 ---- setup ( name = "PyDispatcher", ! version = "1.0.1", description= "Multi-producer-multi-consumer signal dispatching mechanism", author = "Patrick K. O'Brien", |