1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: Deferreds are beautiful! (A Tutorial)</title>
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">Deferreds are beautiful! (A Tutorial)</h1>
9
<div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">A simple example</a></li><li><a href="#auto2">Errbacks</a></li><ul><li><a href="#auto3">Failure in requested operation</a></li><li><a href="#auto4">Exceptions raised in callbacks</a></li><li><a href="#auto5">Exceptions will only be handled by errbacks</a></li><li><a href="#auto6">Handling an exception and continuing on</a></li></ul><li><a href="#auto7">addBoth: the deferred version of finally</a></li><li><a href="#auto8">addCallbacks: decision making based on previous success or failure</a></li><li><a href="#auto9">Hints, tips, common mistakes, and miscellaney</a></li><ul><li><a href="#auto10">The deferred callback chain is stateful</a></li><li><a href="#auto11">Don't call .callback() on deferreds you didn't create!</a></li><li><a href="#auto12">Callbacks can return deferreds</a></li></ul><li><a href="#auto13">Conclusion</a></li></ol></div>
13
<h2>Introduction<a name="auto0"/></h2>
15
<p>Deferreds are quite possibly the single most confusing topic that a
16
newcomer to Twisted has to deal with. I am going to forgo the normal talk
17
about what deferreds are, what they aren't, and why they're used in Twisted.
18
Instead, I'm going show you the logic behind what they
19
<strong>do</strong>.</p>
22
<p>A deferred allows you to encapsulate the logic that you'd normally use to
23
make a series of function calls after receiving a result into a single object.
24
In the examples that follow, I'll first show you what's going to go on behind
25
the scenes in the deferred chain, then show you the deferred API calls that set
26
up that chain. All of these examples are runnable code, so feel free to play
30
<h2>A simple example<a name="auto1"/></h2>
32
First, a simple example so that we have something to talk about:
34
<div class="py-listing"><pre><p class="py-linenumber"> 1
94
</p><span class="py-src-comment">#!/usr/bin/env python</span>
96
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
97
<span class="py-src-comment"># See LICENSE for details.</span>
99
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
100
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
102
<span class="py-src-string">"""
103
Here we have the simplest case, a single callback and a single errback.
104
"""</span>
106
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
108
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
109
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
110
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
111
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
113
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
114
<span class="py-src-keyword">global</span> <span class="py-src-variable">num</span>; <span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
115
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">num</span>,)
116
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
117
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
120
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
121
<span class="py-src-comment"># equivalent to d.callback(result)</span>
123
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
124
<span class="py-src-keyword">try</span>:
125
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
126
<span class="py-src-keyword">except</span>:
127
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
128
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
129
<span class="py-src-keyword">pass</span>
132
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
133
<span class="py-src-keyword">pass</span>
134
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
135
<span class="py-src-keyword">try</span>:
136
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
137
<span class="py-src-keyword">except</span>:
138
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
141
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
142
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
143
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
144
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
146
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
149
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
150
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
151
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
152
<span class="py-src-keyword">global</span> <span class="py-src-variable">num</span>; <span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
153
<span class="py-src-variable">deferredExample</span>()
154
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex.py"><span class="filename">listings/deferred/deferred_ex.py</span></a></div></div>
156
<p>And the output: (since both methods in the example produce the same output,
157
it will only be shown once.) </p>
159
<pre xml:space="preserve">
164
<p>Here we have the simplest case. A deferred with a single callback and a
165
single errback. Normally, a function would create a deferred and hand it back
166
to you when you request an operation that needs to wait for an event for
167
completion. The object you called then does <code>d.callback(result)</code>
168
when the results are in.
171
<p>The thing to notice is that there is only one result that is passed from
172
method to method, and that the result returned from a method is the argument
173
to the next method in the chain. In case of an exception, result is set to an
174
instance of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code>
175
that describes the exception.</p>
177
<h2>Errbacks<a name="auto2"/></h2>
178
<h3>Failure in requested operation<a name="auto3"/></h3>
179
<p>Things don't always go as planned, and sometimes the function that
180
returned the deferred needs to alert the callback chain that an error
183
<div class="py-listing"><pre><p class="py-linenumber"> 1
256
</p><span class="py-src-comment">#!/usr/bin/env python</span>
258
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
259
<span class="py-src-comment"># See LICENSE for details.</span>
261
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
262
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
264
<span class="py-src-string">"""
265
This example is analogous to a function calling .errback(failure)
266
"""</span>
269
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
270
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
272
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
273
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
274
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
275
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
277
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
278
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
279
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
280
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
281
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
283
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
284
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
285
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
286
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
287
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
288
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
291
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
292
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
293
<span class="py-src-keyword">try</span>:
294
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
295
<span class="py-src-keyword">except</span>:
296
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
297
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
298
<span class="py-src-keyword">pass</span>
301
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
302
<span class="py-src-keyword">pass</span>
303
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
304
<span class="py-src-keyword">try</span>:
305
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
306
<span class="py-src-keyword">except</span>:
307
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
310
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>(<span class="py-src-parameter">result</span>):
311
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
312
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
313
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
314
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
316
<span class="py-src-variable">d</span>.<span class="py-src-variable">errback</span>(<span class="py-src-variable">result</span>)
319
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
320
<span class="py-src-variable">result</span> = <span class="py-src-variable">None</span>
321
<span class="py-src-keyword">try</span>:
322
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"*doh*! failure!"</span>
323
<span class="py-src-keyword">except</span>:
324
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
325
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-variable">result</span>)
326
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
327
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
328
<span class="py-src-variable">deferredExample</span>(<span class="py-src-variable">result</span>)
329
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex1a.py"><span class="filename">listings/deferred/deferred_ex1a.py</span></a></div></div>
331
<pre xml:space="preserve">
333
we got an exception: Traceback (most recent call last):
334
--- exception caught here ---
335
File "deferred_ex1a.py", line 73, in ?
336
raise RuntimeError, "*doh*! failure!"
337
exceptions.RuntimeError: *doh*! failure!
340
<p> The important thing to note (as it will come up again in later examples)
341
is that the callback isn't touched, the failure goes right to the errback.
342
Also note that the errback trap()s the expected exception type. If you don't
343
trap the exception, an error will be logged when the deferred is
348
<h3>Exceptions raised in callbacks<a name="auto4"/></h3>
350
<p>Now let's see what happens when <em>our callback</em> raises an
353
<div class="py-listing"><pre><p class="py-linenumber"> 1
432
</p><span class="py-src-comment">#!/usr/bin/env python</span>
434
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
435
<span class="py-src-comment"># See LICENSE for details.</span>
437
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
438
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
440
<span class="py-src-string">"""
441
Here we have a slightly more involved case. The deferred is called back with a
442
result. the first callback returns a value, the second callback, however
443
raises an exception, which is handled by the errback.
444
"""</span>
447
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
448
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
450
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
451
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
452
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
453
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
455
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
456
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
457
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
458
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
459
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
461
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
462
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
463
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
464
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
465
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
466
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
469
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
470
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
471
<span class="py-src-keyword">try</span>:
472
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
473
<span class="py-src-keyword">except</span>:
474
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
475
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
476
<span class="py-src-keyword">pass</span>
479
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
480
<span class="py-src-keyword">try</span>:
481
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
482
<span class="py-src-keyword">except</span>:
483
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
484
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
485
<span class="py-src-keyword">pass</span>
488
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
489
<span class="py-src-keyword">pass</span>
490
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
491
<span class="py-src-keyword">try</span>:
492
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
493
<span class="py-src-keyword">except</span>:
494
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
497
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
498
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
499
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
500
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
501
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
503
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
506
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
507
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
508
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
509
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
510
<span class="py-src-variable">deferredExample</span>()
511
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex1b.py"><span class="filename">listings/deferred/deferred_ex1b.py</span></a></div></div>
513
<p>And the output: (note, tracebacks will be edited slightly to conserve
516
<pre xml:space="preserve">
520
got result: yay! handleResult was successful!
521
about to raise exception
523
we got an exception: Traceback (most recent call last):
524
--- <exception caught here> ---
525
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line
526
326, in _runCallbacks
527
self.result = callback(self.result, *args, **kw)
528
File "./deferred_ex1.py", line 32, in failAtHandlingResult
529
raise RuntimeError, "whoops! we encountered an error"
530
exceptions.RuntimeError: whoops! we encountered an error
533
<p>If your callback raises an exception, the next method to be called will be
534
the next errback in your chain.</p>
537
<h3>Exceptions will only be handled by errbacks<a name="auto5"/></h3>
539
<p>If a callback raises an exception the next method to be called will be next
540
errback in the chain. If the chain is started off with a failure, the first
541
method to be called will be the first errback.</p>
543
<div class="py-listing"><pre><p class="py-linenumber"> 1
634
</p><span class="py-src-comment">#!/usr/bin/env python</span>
636
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
637
<span class="py-src-comment"># See LICENSE for details.</span>
639
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
640
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
642
<span class="py-src-string">"""
643
This example shows an important concept that many deferred newbies
644
(myself included) have trouble understanding.
646
when an error occurs in a callback, the first errback after the error
647
occurs will be the next method called. (in the next example we'll
648
see what happens in the 'chain' after an errback).
649
"""</span>
651
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
652
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
654
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
655
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
656
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
657
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
659
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
660
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
661
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
662
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
663
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
665
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
666
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
667
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
668
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
669
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
670
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
674
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
675
<span class="py-src-comment"># equivalent to d.callback(result)</span>
677
<span class="py-src-comment"># now, let's make the error happen in the first callback</span>
679
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
680
<span class="py-src-keyword">try</span>:
681
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
682
<span class="py-src-keyword">except</span>:
683
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
684
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
685
<span class="py-src-keyword">pass</span>
688
<span class="py-src-comment"># note: this callback will be skipped because</span>
689
<span class="py-src-comment"># result is a failure</span>
691
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
692
<span class="py-src-keyword">try</span>:
693
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
694
<span class="py-src-keyword">except</span>:
695
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
696
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
697
<span class="py-src-keyword">pass</span>
700
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
701
<span class="py-src-keyword">pass</span>
702
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
703
<span class="py-src-keyword">try</span>:
704
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
705
<span class="py-src-keyword">except</span>:
706
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
710
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
711
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
712
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
713
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
714
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
716
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
719
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
720
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
721
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
722
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
723
<span class="py-src-variable">deferredExample</span>()
724
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex2.py"><span class="filename">listings/deferred/deferred_ex2.py</span></a></div></div>
726
<pre xml:space="preserve">
729
about to raise exception
731
we got an exception: Traceback (most recent call last):
732
File "./deferred_ex2.py", line 85, in ?
733
nonDeferredExample("success")
734
--- <exception caught here> ---
735
File "./deferred_ex2.py", line 46, in nonDeferredExample
736
result = failAtHandlingResult(result)
737
File "./deferred_ex2.py", line 35, in failAtHandlingResult
738
raise RuntimeError, "whoops! we encountered an error"
739
exceptions.RuntimeError: whoops! we encountered an error
742
<p>You can see that our second callback, handleResult was not called because
743
failAtHandlingResult raised an exception</p>
745
<h3>Handling an exception and continuing on<a name="auto6"/></h3>
747
<p>In this example, we see an errback handle an exception raised in the
748
preceeding callback. Take note that it could just as easily been an exception
749
from <strong>any other</strong> preceeding method. You'll see that after the
750
exception is handled in the errback (i.e. the errback does not return a
751
failure or raise an exception) the chain continues on with the next
754
<div class="py-listing"><pre><p class="py-linenumber"> 1
854
</p><span class="py-src-comment">#!/usr/bin/env python</span>
856
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
857
<span class="py-src-comment"># See LICENSE for details.</span>
859
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
860
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
862
<span class="py-src-string">"""
863
Now we see how an errback can handle errors. if an errback
864
does not raise an exception, the next callback in the chain
866
"""</span>
868
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
869
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
872
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
873
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
874
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
875
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
876
<span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
878
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
879
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
880
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
881
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
882
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
884
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
885
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
886
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
887
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
888
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
889
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
891
<span class="py-src-keyword">def</span> <span class="py-src-identifier">callbackAfterErrback</span>(<span class="py-src-parameter">result</span>):
892
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
893
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
894
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
898
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
899
<span class="py-src-comment"># equivalent to d.callback(result)</span>
901
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
902
<span class="py-src-keyword">try</span>:
903
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
904
<span class="py-src-keyword">except</span>:
905
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
906
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
907
<span class="py-src-keyword">pass</span>
910
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
911
<span class="py-src-keyword">try</span>:
912
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
913
<span class="py-src-keyword">except</span>:
914
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
915
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
916
<span class="py-src-keyword">pass</span>
919
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
920
<span class="py-src-keyword">pass</span>
921
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
922
<span class="py-src-keyword">try</span>:
923
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
924
<span class="py-src-keyword">except</span>:
925
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
928
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
929
<span class="py-src-keyword">try</span>:
930
<span class="py-src-variable">result</span> = <span class="py-src-variable">callbackAfterErrback</span>(<span class="py-src-variable">result</span>)
931
<span class="py-src-keyword">except</span>:
932
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
933
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
934
<span class="py-src-keyword">pass</span>
938
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
939
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
940
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
941
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
942
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
943
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">callbackAfterErrback</span>)
945
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
948
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
949
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
950
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
951
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
952
<span class="py-src-variable">deferredExample</span>()
953
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex3.py"><span class="filename">listings/deferred/deferred_ex3.py</span></a></div></div>
955
<pre xml:space="preserve">
959
got result: yay! handleResult was successful!
960
about to raise exception
962
we got an exception: Traceback (most recent call last):
963
File "./deferred_ex3.py", line 97, in <module>
965
File "./deferred_ex3.py", line 90, in deferredExample
966
d.callback("success")
967
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 243, in callback
968
self._startRunCallbacks(result)
969
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 312, in _startRunCallbacks
971
--- <exception caught here> ---
972
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line 328, in _runCallbacks
973
self.result = callback(self.result, *args, **kw)
974
File "./deferred_ex3.py", line 34, in failAtHandlingResult
975
raise RuntimeError, "whoops! we encountered an error"
976
exceptions.RuntimeError: whoops! we encountered an error
979
got result: okay, continue on
982
<h2>addBoth: the deferred version of <em>finally</em><a name="auto7"/></h2>
984
<p>Now we see how deferreds do <strong>finally</strong>, with .addBoth. The
985
callback that gets added as addBoth will be called if the result is a failure
986
or non-failure. We'll also see in this example, that our doThisNoMatterWhat()
987
method follows a common idiom in deferred callbacks by acting as a passthru,
988
returning the value that it received to allow processing the chain to
989
continue, but appearing transparent in terms of the result.</p>
991
<div class="py-listing"><pre><p class="py-linenumber"> 1
1095
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1097
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1098
<span class="py-src-comment"># See LICENSE for details.</span>
1100
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1101
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
1103
<span class="py-src-string">"""
1104
Now we'll see what happens when you use 'addBoth'.
1105
"""</span>
1107
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
1108
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1111
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
1112
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
1113
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
1114
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1115
<span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
1117
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
1118
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1119
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1120
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1121
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
1123
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
1124
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1125
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1126
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1127
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
1128
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
1130
<span class="py-src-keyword">def</span> <span class="py-src-identifier">doThisNoMatterWhat</span>(<span class="py-src-parameter">arg</span>):
1131
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1132
<span class="py-src-keyword">print</span> <span class="py-src-string">"both %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1133
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot argument %r"</span> % (<span class="py-src-variable">arg</span>,)
1134
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoing something very important"</span>
1135
<span class="py-src-comment"># we pass the argument we received to the next phase here</span>
1136
<span class="py-src-keyword">return</span> <span class="py-src-variable">arg</span>
1140
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
1141
<span class="py-src-comment"># equivalent to d.callback(result)</span>
1143
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1144
<span class="py-src-keyword">try</span>:
1145
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
1146
<span class="py-src-keyword">except</span>:
1147
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1148
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1149
<span class="py-src-keyword">pass</span>
1152
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1153
<span class="py-src-keyword">try</span>:
1154
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
1155
<span class="py-src-keyword">except</span>:
1156
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1157
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1158
<span class="py-src-keyword">pass</span>
1161
<span class="py-src-comment"># ---- this is equivalent to addBoth(doThisNoMatterWhat)</span>
1163
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>):
1164
<span class="py-src-keyword">try</span>:
1165
<span class="py-src-variable">result</span> = <span class="py-src-variable">doThisNoMatterWhat</span>(<span class="py-src-variable">result</span>)
1166
<span class="py-src-keyword">except</span>:
1167
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1168
<span class="py-src-keyword">else</span>:
1169
<span class="py-src-keyword">try</span>:
1170
<span class="py-src-variable">result</span> = <span class="py-src-variable">doThisNoMatterWhat</span>(<span class="py-src-variable">result</span>)
1171
<span class="py-src-keyword">except</span>:
1172
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1175
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1176
<span class="py-src-keyword">pass</span>
1177
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1178
<span class="py-src-keyword">try</span>:
1179
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
1180
<span class="py-src-keyword">except</span>:
1181
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1184
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
1185
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1186
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
1187
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
1188
<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">doThisNoMatterWhat</span>)
1189
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1191
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
1194
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1195
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
1196
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
1197
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1198
<span class="py-src-variable">deferredExample</span>()
1199
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex4.py"><span class="filename">listings/deferred/deferred_ex4.py</span></a></div></div>
1201
<pre xml:space="preserve">
1205
got result: yay! handleResult was successful!
1206
about to raise exception
1208
got argument <twisted.python.failure.Failure exceptions.RuntimeError>
1209
doing something very important
1211
we got an exception: Traceback (most recent call last):
1212
--- <exception caught here> ---
1213
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line
1214
326, in _runCallbacks
1215
self.result = callback(self.result, *args, **kw)
1216
File "./deferred_ex4.py", line 32, in failAtHandlingResult
1217
raise RuntimeError, "whoops! we encountered an error"
1218
exceptions.RuntimeError: whoops! we encountered an error
1221
<p>You can see that the errback is called, (and consequently, the failure is
1222
trapped). This is because doThisNoMatterWhat method returned the value it
1223
received, a failure.</p>
1225
<h2>addCallbacks: decision making based on previous success or failure<a name="auto8"/></h2>
1227
<p>As we've been seeing in the examples, the callback is a pair of
1228
callback/errback. Using addCallback or addErrback is actually a special case
1229
where one of the pair is a pass statement. If you want to make a decision
1230
based on whether or not the previous result in the chain was a failure or not
1231
(which is very rare, but included here for completeness), you use
1232
addCallbacks. Note that this is <strong>not</strong> the same thing as an
1233
addCallback followed by an addErrback.</p>
1236
<div class="py-listing"><pre><p class="py-linenumber"> 1
1372
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1374
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1375
<span class="py-src-comment"># See LICENSE for details.</span>
1377
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1378
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
1380
<span class="py-src-string">"""
1381
Now comes the more nuanced addCallbacks, which allows us to make a
1382
yes/no (branching) decision based on whether the result at a given point is
1384
"""</span>
1386
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
1387
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1390
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
1391
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
1392
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
1393
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1394
<span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
1396
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
1397
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1398
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1399
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1400
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
1402
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
1403
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1404
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1405
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1406
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
1407
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
1409
<span class="py-src-keyword">def</span> <span class="py-src-identifier">yesDecision</span>(<span class="py-src-parameter">result</span>):
1410
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1411
<span class="py-src-keyword">print</span> <span class="py-src-string">"yes decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1412
<span class="py-src-keyword">print</span> <span class="py-src-string">"\twasn't a failure, so we can plow ahead"</span>
1413
<span class="py-src-keyword">return</span> <span class="py-src-string">"go ahead!"</span>
1415
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecision</span>(<span class="py-src-parameter">result</span>):
1416
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1417
<span class="py-src-variable">result</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1418
<span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1419
<span class="py-src-keyword">print</span> <span class="py-src-string">"\t*doh*! a failure! quick! damage control!"</span>
1420
<span class="py-src-keyword">return</span> <span class="py-src-string">"damage control successful!"</span>
1424
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
1426
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1427
<span class="py-src-keyword">try</span>:
1428
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
1429
<span class="py-src-keyword">except</span>:
1430
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1431
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1432
<span class="py-src-keyword">pass</span>
1435
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
1437
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1438
<span class="py-src-keyword">try</span>:
1439
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
1440
<span class="py-src-keyword">except</span>:
1441
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1442
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1443
<span class="py-src-keyword">try</span>:
1444
<span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>)
1445
<span class="py-src-keyword">except</span>:
1446
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1449
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1450
<span class="py-src-keyword">try</span>:
1451
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
1452
<span class="py-src-keyword">except</span>:
1453
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1454
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1455
<span class="py-src-keyword">pass</span>
1458
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
1460
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1461
<span class="py-src-keyword">try</span>:
1462
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
1463
<span class="py-src-keyword">except</span>:
1464
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1465
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1466
<span class="py-src-keyword">try</span>:
1467
<span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>)
1468
<span class="py-src-keyword">except</span>:
1469
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1472
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1473
<span class="py-src-keyword">try</span>:
1474
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
1475
<span class="py-src-keyword">except</span>:
1476
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1477
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1478
<span class="py-src-keyword">pass</span>
1481
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1482
<span class="py-src-keyword">pass</span>
1483
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1484
<span class="py-src-keyword">try</span>:
1485
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
1486
<span class="py-src-keyword">except</span>:
1487
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1490
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
1491
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1492
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
1493
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>) <span class="py-src-comment"># noDecision will be called</span>
1494
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - A -</span>
1495
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>) <span class="py-src-comment"># yesDecision will be called</span>
1496
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
1497
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1499
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
1502
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1503
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
1504
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
1505
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1506
<span class="py-src-variable">deferredExample</span>()
1507
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex5.py"><span class="filename">listings/deferred/deferred_ex5.py</span></a></div></div>
1509
<pre xml:space="preserve">
1512
about to raise exception
1514
*doh*! a failure! quick! damage control!
1516
got result: damage control successful!
1518
wasn't a failure, so we can plow ahead
1520
got result: go ahead!
1523
<p>Notice that our errback is never called. The noDecision method returns a
1524
non-failure so processing continues with the next callback. If we wanted to
1525
skip the callback at "- A -" because of the error, but do some kind of
1526
processing in response to the error, we would have used a passthru, and
1527
returned the failure we received, as we see in this next example: </p>
1529
<div class="py-listing"><pre><p class="py-linenumber"> 1
1677
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1679
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1680
<span class="py-src-comment"># See LICENSE for details.</span>
1682
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1683
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
1685
<span class="py-src-string">"""
1686
Now comes the more nuanced addCallbacks, which allows us to make a
1687
yes/no (branching) decision based on whether the result at a given point is
1690
here, we return the failure from noDecisionPassthru, the errback argument to
1691
the first addCallbacks method invocation, and see what happens.
1692
"""</span>
1694
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
1695
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1698
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
1699
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
1700
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
1701
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1702
<span class="py-src-keyword">return</span> <span class="py-src-string">"okay, continue on"</span>
1704
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
1705
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1706
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1707
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1708
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
1710
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
1711
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1712
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1713
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1714
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
1715
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
1717
<span class="py-src-keyword">def</span> <span class="py-src-identifier">yesDecision</span>(<span class="py-src-parameter">result</span>):
1718
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1719
<span class="py-src-keyword">print</span> <span class="py-src-string">"yes decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1720
<span class="py-src-keyword">print</span> <span class="py-src-string">"\twasn't a failure, so we can plow ahead"</span>
1721
<span class="py-src-keyword">return</span> <span class="py-src-string">"go ahead!"</span>
1723
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecision</span>(<span class="py-src-parameter">result</span>):
1724
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1725
<span class="py-src-variable">result</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1726
<span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1727
<span class="py-src-keyword">print</span> <span class="py-src-string">"\t*doh*! a failure! quick! damage control!"</span>
1728
<span class="py-src-keyword">return</span> <span class="py-src-string">"damage control successful!"</span>
1730
<span class="py-src-keyword">def</span> <span class="py-src-identifier">noDecisionPassthru</span>(<span class="py-src-parameter">result</span>):
1731
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1732
<span class="py-src-keyword">print</span> <span class="py-src-string">"no decision %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1733
<span class="py-src-keyword">print</span> <span class="py-src-string">"\t*doh*! a failure! don't know what to do, returning failure!"</span>
1734
<span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
1737
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
1739
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1740
<span class="py-src-keyword">try</span>:
1741
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
1742
<span class="py-src-keyword">except</span>:
1743
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1744
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1745
<span class="py-src-keyword">pass</span>
1748
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
1750
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1751
<span class="py-src-keyword">try</span>:
1752
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
1753
<span class="py-src-keyword">except</span>:
1754
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1755
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1756
<span class="py-src-keyword">try</span>:
1757
<span class="py-src-variable">result</span> = <span class="py-src-variable">noDecisionPassthru</span>(<span class="py-src-variable">result</span>)
1758
<span class="py-src-keyword">except</span>:
1759
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1762
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1763
<span class="py-src-keyword">try</span>:
1764
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
1765
<span class="py-src-keyword">except</span>:
1766
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1767
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1768
<span class="py-src-keyword">pass</span>
1771
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
1773
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1774
<span class="py-src-keyword">try</span>:
1775
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
1776
<span class="py-src-keyword">except</span>:
1777
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1778
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1779
<span class="py-src-keyword">try</span>:
1780
<span class="py-src-variable">result</span> = <span class="py-src-variable">noDecision</span>(<span class="py-src-variable">result</span>)
1781
<span class="py-src-keyword">except</span>:
1782
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1785
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1786
<span class="py-src-keyword">try</span>:
1787
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
1788
<span class="py-src-keyword">except</span>:
1789
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1790
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1791
<span class="py-src-keyword">pass</span>
1794
<span class="py-src-keyword">if</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">isinstance</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>): <span class="py-src-comment"># ---- callback</span>
1795
<span class="py-src-keyword">pass</span>
1796
<span class="py-src-keyword">else</span>: <span class="py-src-comment"># ---- errback</span>
1797
<span class="py-src-keyword">try</span>:
1798
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleFailure</span>(<span class="py-src-variable">result</span>)
1799
<span class="py-src-keyword">except</span>:
1800
<span class="py-src-variable">result</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">Failure</span>()
1803
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
1804
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1805
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
1807
<span class="py-src-comment"># noDecisionPassthru will be called</span>
1808
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecisionPassthru</span>)
1809
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - A -</span>
1811
<span class="py-src-comment"># noDecision will be called</span>
1812
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">yesDecision</span>, <span class="py-src-variable">noDecision</span>)
1813
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>) <span class="py-src-comment"># - B -</span>
1814
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1816
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
1819
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1820
<span class="py-src-variable">behindTheScenes</span>(<span class="py-src-string">"success"</span>)
1821
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
1822
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1823
<span class="py-src-variable">deferredExample</span>()
1824
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex6.py"><span class="filename">listings/deferred/deferred_ex6.py</span></a></div></div>
1826
<pre xml:space="preserve">
1829
about to raise exception
1831
*doh*! a failure! don't know what to do, returning failure!
1833
*doh*! a failure! quick! damage control!
1835
got result: damage control successful!
1838
<p>Two things to note here. First, "- A -" was skipped, like we wanted it to,
1839
and the second thing is that after "- A -", noDecision is called, because
1840
<strong>it is the next errback that exists in the chain</strong>. It returns a
1841
non-failure, so processing continues with the next callback at "- B -", and
1842
the errback at the end of the chain is never called </p>
1844
<h2>Hints, tips, common mistakes, and miscellaney<a name="auto9"/></h2>
1846
<h3>The deferred callback chain is stateful<a name="auto10"/></h3>
1848
<p>A deferred that has been called back will call its addCallback and
1849
addErrback methods as appropriate in the order they are added, when they are
1850
added. So we see in the following example, deferredExample1 and
1851
deferredExample2 are equivalent. The first sets up the processing chain
1852
beforehand and then executes it, the other executes the chain as it is being
1853
constructed. This is because deferreds are <em>stateful</em>. </p>
1855
<div class="py-listing"><pre><p class="py-linenumber"> 1
1916
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1918
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1919
<span class="py-src-comment"># See LICENSE for details.</span>
1921
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1922
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
1924
<span class="py-src-string">"""
1925
The deferred callback chain is stateful, and can be executed before
1926
or after all callbacks have been added to the chain
1927
"""</span>
1929
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
1930
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1932
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
1933
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
1934
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
1935
<span class="py-src-variable">f</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">RuntimeError</span>)
1937
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleResult</span>(<span class="py-src-parameter">result</span>):
1938
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1939
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1940
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1941
<span class="py-src-keyword">return</span> <span class="py-src-string">"yay! handleResult was successful!"</span>
1943
<span class="py-src-keyword">def</span> <span class="py-src-identifier">failAtHandlingResult</span>(<span class="py-src-parameter">result</span>):
1944
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
1945
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
1946
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
1947
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tabout to raise exception"</span>
1948
<span class="py-src-keyword">raise</span> <span class="py-src-variable">RuntimeError</span>, <span class="py-src-string">"whoops! we encountered an error"</span>
1950
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample1</span>():
1951
<span class="py-src-comment"># this is another common idiom, since all add* methods</span>
1952
<span class="py-src-comment"># return the deferred instance, you can just chain your</span>
1953
<span class="py-src-comment"># calls to addCallback and addErrback</span>
1955
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>
1956
).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>
1957
).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1959
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
1961
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample2</span>():
1962
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1964
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"success"</span>)
1966
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
1967
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>)
1968
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1971
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1972
<span class="py-src-variable">deferredExample1</span>()
1973
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
1974
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1975
<span class="py-src-variable">deferredExample2</span>()
1976
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex7.py"><span class="filename">listings/deferred/deferred_ex7.py</span></a></div></div>
1978
<pre xml:space="preserve">
1981
about to raise exception
1983
we got an exception: Traceback (most recent call last):
1984
--- <exception caught here> ---
1985
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line
1986
326, in _runCallbacks
1987
self.result = callback(self.result, *args, **kw)
1988
File "./deferred_ex7.py", line 35, in failAtHandlingResult
1989
raise RuntimeError, "whoops! we encountered an error"
1990
exceptions.RuntimeError: whoops! we encountered an error
1993
-------------------------------------------------
1997
about to raise exception
1999
we got an exception: Traceback (most recent call last):
2000
--- <exception caught here> ---
2001
File "/home/slyphon/Projects/Twisted/trunk/twisted/internet/defer.py", line
2002
326, in _runCallbacks
2003
self.result = callback(self.result, *args, **kw)
2004
File "./deferred_ex7.py", line 35, in failAtHandlingResult
2005
raise RuntimeError, "whoops! we encountered an error"
2006
exceptions.RuntimeError: whoops! we encountered an error
2009
<p>This example also shows you the common idiom of chaining calls to
2010
addCallback and addErrback.
2013
<h3>Don't call .callback() on deferreds you didn't create!<a name="auto11"/></h3>
2015
<p>It is an error to reinvoke deferreds callback or errback method, therefore
2016
if you didn't create a deferred, <strong>do not under any
2017
circumstances</strong> call its callback or errback. doing so will raise
2020
<h3>Callbacks can return deferreds<a name="auto12"/></h3>
2022
<p>If you need to call a method that returns a deferred within your callback
2023
chain, just return that deferred, and the result of the secondary deferred's
2024
processing chain will become the result that gets passed to the next callback
2025
of the primary deferreds processing chain </p>
2027
<div class="py-listing"><pre><p class="py-linenumber"> 1
2093
</p><span class="py-src-comment">#!/usr/bin/env python</span>
2095
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
2096
<span class="py-src-comment"># See LICENSE for details.</span>
2098
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
2099
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">failure</span>, <span class="py-src-variable">util</span>
2102
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
2103
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
2104
<span class="py-src-variable">let</span> = <span class="py-src-string">'a'</span>
2106
<span class="py-src-keyword">def</span> <span class="py-src-identifier">incrLet</span>(<span class="py-src-parameter">cls</span>):
2107
<span class="py-src-variable">cls</span>.<span class="py-src-variable">let</span> = <span class="py-src-variable">chr</span>(<span class="py-src-variable">ord</span>(<span class="py-src-variable">cls</span>.<span class="py-src-variable">let</span>) + <span class="py-src-number">1</span>)
2108
<span class="py-src-variable">incrLet</span> = <span class="py-src-variable">classmethod</span>(<span class="py-src-variable">incrLet</span>)
2111
<span class="py-src-keyword">def</span> <span class="py-src-identifier">handleFailure</span>(<span class="py-src-parameter">f</span>):
2112
<span class="py-src-keyword">print</span> <span class="py-src-string">"errback"</span>
2113
<span class="py-src-keyword">print</span> <span class="py-src-string">"we got an exception: %s"</span> % (<span class="py-src-variable">f</span>.<span class="py-src-variable">getTraceback</span>(),)
2114
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
2116
<span class="py-src-keyword">def</span> <span class="py-src-identifier">subCb_B</span>(<span class="py-src-parameter">result</span>):
2117
<span class="py-src-keyword">print</span> <span class="py-src-string">"sub-callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">let</span>,)
2118
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">incrLet</span>()
2119
<span class="py-src-variable">s</span> = <span class="py-src-string">" beautiful!"</span>
2120
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tadding %r to result"</span> % (<span class="py-src-variable">s</span>,)
2121
<span class="py-src-variable">result</span> += <span class="py-src-variable">s</span>
2122
<span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
2124
<span class="py-src-keyword">def</span> <span class="py-src-identifier">subCb_A</span>(<span class="py-src-parameter">result</span>):
2125
<span class="py-src-keyword">print</span> <span class="py-src-string">"sub-callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">let</span>,)
2126
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">incrLet</span>()
2127
<span class="py-src-variable">s</span> = <span class="py-src-string">" are "</span>
2128
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tadding %r to result"</span> % (<span class="py-src-variable">s</span>,)
2129
<span class="py-src-variable">result</span> += <span class="py-src-variable">s</span>
2130
<span class="py-src-keyword">return</span> <span class="py-src-variable">result</span>
2132
<span class="py-src-keyword">def</span> <span class="py-src-identifier">mainCb_1</span>(<span class="py-src-parameter">result</span>):
2133
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
2134
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
2135
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
2136
<span class="py-src-variable">result</span> += <span class="py-src-string">" Deferreds "</span>
2138
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">subCb_A</span>
2139
).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">subCb_B</span>)
2140
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">result</span>)
2141
<span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
2143
<span class="py-src-keyword">def</span> <span class="py-src-identifier">mainCb_2</span>(<span class="py-src-parameter">result</span>):
2144
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> += <span class="py-src-number">1</span>
2145
<span class="py-src-keyword">print</span> <span class="py-src-string">"callback %s"</span> % (<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span>,)
2146
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot result: %s"</span> % (<span class="py-src-variable">result</span>,)
2149
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample</span>():
2150
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">mainCb_1</span>
2151
).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">mainCb_2</span>)
2153
<span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-string">"I hope you'll agree: "</span>)
2156
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
2157
<span class="py-src-variable">deferredExample</span>()
2158
</pre><div class="caption">Source listing - <a href="listings/deferred/deferred_ex8.py"><span class="filename">listings/deferred/deferred_ex8.py</span></a></div></div>
2160
<pre xml:space="preserve">
2162
got result: I hope you'll agree:
2164
adding ' are ' to result
2166
adding ' beautiful!' to result
2168
got result: I hope you'll agree: Deferreds are beautiful!
2171
<h2>Conclusion<a name="auto13"/></h2>
2173
<p>Deferreds can be confusing, but only because they're so elegant and simple.
2174
There is a lot of logical power that can expressed with a deferred's
2175
processing chain, and once you see what's going on behind the curtain, it's a
2176
lot easier to understand how to make use of what deferreds have to offer.</p>
2180
<p><a href="index.html">Index</a></p>
2181
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'