1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
|
<!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>
<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 <a href="https://launchpad.net/pydispatcher">project</a>
aims
to include various enhancements to the recipe developed during use in
various applications. It is primarily maintained by <a href="http://www.vrplumber.com">Mike Fletcher</a>. A derivative
of the project provides the Django web framework's "signal" system.<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
as a sender, and any callable object can act as a receiver. There
is no need to inherit from a particular class or provide a particular
interface on the object.<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
which are not appropriate for the particular receiver. This
allows registering very simple functions dealing with general messages,
while still allowing natural passing of arguments to higher level
functions.<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 Python Package Index (PyPI). To
install, run:<br>
</p>
<pre>pip install PyDispatcher<br></pre>
<p>PyDispatcher does not include any binary packages, so there should
be no issues in installation. PyDispatcher is maintained on the
LaunchPad project in bzr. To help develop, check out the project
like so:</p>
<pre>bzr branch lp:~mcfletch/pydispatcher/working<br></pre>
<p>You can either send a pull request via LaunchPad or email a
patch-set via:</p>
<pre>bzr send --mail-to=mcfletch@vrplumber.com<br></pre>
<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,
it is <strong>strongly
recommended</strong> that you use <strong>Python 2.2.3</strong> or
later
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
recommended</strong> that you use <strong>Python 2.3.3</strong> or
later
when using PyDispatcher. This bug-fix will not be ported back to
the Python 2.2.x branch, so if you are using Python 2.2.3 you may
encounter this situation.
</p>
<h2>Documentation</h2>
<p>You can find usage samples in the examples directory of the
distribution. The dispatcher module's <a href="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>Usage</h2>
<p>To set up a function to receive signals:</p>
<pre>from pydispatch import dispatcher<br>SIGNAL = 'my-first-signal'<br><br>def handle_event( sender ):<br> """Simple event handler"""<br> print 'Signal was sent by', sender<br>dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any )<br></pre>
<p>The use of the Any object allows the handler to listen for messages
from any Sender or to listen to Any message being sent. To send
messages:</p>
<pre>first_sender = object()<br>second_sender = {}<br>def main( ):<br> dispatcher.send( signal=SIGNAL, sender=first_sender )<br> dispatcher.send( signal=SIGNAL, sender=second_sender )<br></pre>
<p>Which causes the following to be printed:</p>
<pre>Signal was sent by <object object at 0x196a090><br>Signal was sent by {}<br></pre>
<h3>Handler Functions</h3>
<p>Handler functions in PyDispatcher are relatively loose in their
definition. A handler can simply declare the parameters it would
like to receive and receive only those parameters when the signal is
sent. The sender can include extra parameters for those handlers
which require them without worrying about whether a more generic
handler can accept them:</p>
<pre>def handle_specific_event( sender, moo ):<br> """Handle a simple event, requiring a "moo" parameter"""<br> print 'Specialized event for %(sender)s moo=%(moo)r'%locals()<br>dispatcher.connect( handle_specific_event, signal=SIGNAL2, sender=dispatcher.Any )<br></pre>
<p>This connection requires that all senders of the particular signal
send a "moo" parameter, but a handler that listens for all events and
does not provide a "moo" parameter would silently ignore the sender
having passed a "moo".</p>
<p>2 parameters are always available to handler functions if they would like to use them:</p>
<table style="text-align: left; width: 100%;" border="1" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<th>Parameter<br>
</th>
<th>Value<br>
</th>
</tr>
<tr>
<td>sender<br>
</td>
<td>Object from/for which the event was sent, can be dispatcher.Anonymous for anonymous signals<br>
</td>
</tr>
<tr>
<td>signal<br>
</td>
<td>Signal object used when sending<br>
</td>
</tr>
</tbody>
</table>
<p>Positional arguments and named arguments are passed through, but if
positional arguments are used, they will fill in the parameters of the
receiver in order and cause conflicts if named parameters are specified
which match their names. Generally it is advisable to use named
arguments when defining sending messages.</p>
<h3>Real World Examples</h3>
<p>OpenGLContext uses PyDispatcher to provide a link between PyVRML97
(model level) and OpenGLContext (the controller and view levels).
Changes to fields in the model <a href="http://bazaar.launchpad.net/%7Emcfletch/pyvrml97/trunk/view/head:/vrml/field.py#L81">send events</a>, as do changes to <a href="http://bazaar.launchpad.net/%7Emcfletch/pyvrml97/trunk/view/head:/vrml/olist.py">object lists</a>. A <a href="http://bazaar.launchpad.net/%7Emcfletch/pyvrml97/trunk/view/head:/vrml/cache.py">cache</a> observes these changes and allows the view/model level to <a href="http://bazaar.launchpad.net/%7Emcfletch/openglcontext/trunk/view/head:/OpenGLContext/scenegraph/box.py">register dependencies</a>
on particular fields of particular nodes. The result is that
rendering code can cache data extensively and have the caches
consistently invalidated when their data-dependencies are changed.</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>
<li><a href="https://code.djangoproject.com/browser/django/trunk/django/dispatch">django.dispatch (Signals)</a></li>
<ul>
<li>Rewritten with a more limited interface, but higher
performance; requires that signals be objects of a given type, and
eliminates Any registrations. Registrations are on the signal
objects.<br>
</li>
</ul>
</ul>
<h2>Release Notes</h2>
<ul>
<li>Version 2.0.5</li>
<ul>
<li>Python 3.x support via shared code-base (not 2to3). Python 2.x is still the primary development target</li>
</ul>
<li>Version 2.0.3</li>
<ul>
<li>Support for Python 3.2 (via 2to3) added, Python 2.x is still
the primary development target<br>
</li>
</ul>
<li>Version 2.0.2</li>
<ul>
<li>Further packaging fixes.<br>
</li>
</ul>
<li>Version 2.0.1 (this version and all previous versions are
available from the old <a href="http://sourceforge.net/projects/pydispatcher/files/pydispatcher/">SourceForge
project</a>)<br>
</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 <a href="http://sourceforge.net">SourceForge Open-Source</a> project.</p>
</body></html>
|