1
<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: Deferreds are beautiful! (A Tutorial)</title><link href="stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">Deferreds are beautiful! (A Tutorial)</h1><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><div class="content"><span></span><h2>Introduction<a name="auto0"></a></h2><p>Deferreds are quite possibly the single most confusing topic that a
1
<?xml version="1.0" encoding="utf-8"?>
3
PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
4
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
5
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
7
<title>Twisted Documentation: Deferreds are beautiful! (A Tutorial)</title>
8
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
11
<body bgcolor="white">
12
<h1 class="title">Deferreds are beautiful! (A Tutorial)</h1>
13
<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>
17
<h2>Introduction<a name="auto0"/></h2>
19
<p>Deferreds are quite possibly the single most confusing topic that a
3
20
newcomer to Twisted has to deal with. I am going to forgo the normal talk
4
21
about what deferreds are, what they aren't, and why they're used in Twisted.
5
22
Instead, I'm going show you the logic behind what they
6
<strong>do</strong>.</p><p>A deferred allows you to encapsulate the logic that you'd normally use to
23
<strong>do</strong>.</p>
26
<p>A deferred allows you to encapsulate the logic that you'd normally use to
7
27
make a series of function calls after receiving a result into a single object.
8
28
In the examples that follow, I'll first show you what's going to go on behind
9
29
the scenes in the deferred chain, then show you the deferred API calls that set
10
30
up that chain. All of these examples are runnable code, so feel free to play
11
around with them.</p><h2>A simple example<a name="auto1"></a></h2>
34
<h2>A simple example<a name="auto1"/></h2>
13
36
First, a simple example so that we have something to talk about:
15
<div class="py-listing"><pre>
16
<span class="py-src-comment">#!/usr/bin/python
38
<div class="py-listing"><pre><p class="py-linenumber"> 1
98
</p><span class="py-src-comment">#!/usr/bin/env python</span>
100
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
101
<span class="py-src-comment"># See LICENSE for details.</span>
18
103
<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>
19
104
<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>
21
106
<span class="py-src-string">"""
22
here we have the simplest case, a single callback and a single errback
107
Here we have the simplest case, a single callback and a single errback.
23
108
"""</span>
25
110
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
39
124
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
40
<span class="py-src-comment"># equivalent to d.callback(result)
125
<span class="py-src-comment"># equivalent to d.callback(result)</span>
42
127
<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>
43
128
<span class="py-src-keyword">try</span>:
44
129
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
70
155
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
71
156
<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>
72
157
<span class="py-src-variable">deferredExample</span>()
73
</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><p>And the output: (since both methods in the example produce the same output,
74
it will only be shown once.) </p><pre>
158
</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>
160
<p>And the output: (since both methods in the example produce the same output,
161
it will only be shown once.) </p>
163
<pre xml:space="preserve">
76
165
got result: success
77
</pre><p>Here we have the simplest case. A deferred with a single callback and a
168
<p>Here we have the simplest case. A deferred with a single callback and a
78
169
single errback. Normally, a function would create a deferred and hand it back
79
170
to you when you request an operation that needs to wait for an event for
80
171
completion. The object you called then does <code>d.callback(result)</code>
81
172
when the results are in.
82
</p><p>The thing to notice is that there is only one result that is passed from
175
<p>The thing to notice is that there is only one result that is passed from
83
176
method to method, and that the result returned from a method is the argument
84
177
to the next method in the chain. In case of an exception, result is set to an
85
instance of <code class="API"><a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code>
86
that describes the exception.</p><h2>Errbacks<a name="auto2"></a></h2><h3>Failure in requested operation<a name="auto3"></a></h3><p>Things don't always go as planned, and sometimes the function that
178
instance of <code class="API"><a href="http://twistedmatrix.com/documents/9.0.0/api/twisted.python.failure.Failure.html" title="twisted.python.failure.Failure">Failure</a></code>
179
that describes the exception.</p>
181
<h2>Errbacks<a name="auto2"/></h2>
182
<h3>Failure in requested operation<a name="auto3"/></h3>
183
<p>Things don't always go as planned, and sometimes the function that
87
184
returned the deferred needs to alert the callback chain that an error
88
has occurred.</p><div class="py-listing"><pre>
89
<span class="py-src-comment">#!/usr/bin/python
187
<div class="py-listing"><pre><p class="py-linenumber"> 1
260
</p><span class="py-src-comment">#!/usr/bin/env python</span>
262
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
263
<span class="py-src-comment"># See LICENSE for details.</span>
91
265
<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>
92
266
<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>
94
268
<span class="py-src-string">"""
95
this example is analogous to a function calling .errback(failure)
269
This example is analogous to a function calling .errback(failure)
96
270
"""</span>
156
330
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
157
331
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
158
332
<span class="py-src-variable">deferredExample</span>(<span class="py-src-variable">result</span>)
159
</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><pre>
333
</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>
335
<pre xml:space="preserve">
161
337
we got an exception: Traceback (most recent call last):
162
338
--- exception caught here ---
163
339
File "deferred_ex1a.py", line 73, in ?
164
340
raise RuntimeError, "*doh*! failure!"
165
341
exceptions.RuntimeError: *doh*! failure!
166
</pre><p> The important thing to note (as it will come up again in later examples)
344
<p> The important thing to note (as it will come up again in later examples)
167
345
is that the callback isn't touched, the failure goes right to the errback.
168
346
Also note that the errback trap()s the expected exception type. If you don't
169
347
trap the exception, an error will be logged when the deferred is
170
348
garbage-collected.
171
</p><h3>Exceptions raised in callbacks<a name="auto4"></a></h3><p>Now let's see what happens when <em>our callback</em> raises an
172
exception</p><div class="py-listing"><pre>
173
<span class="py-src-comment">#!/usr/bin/python
352
<h3>Exceptions raised in callbacks<a name="auto4"/></h3>
354
<p>Now let's see what happens when <em>our callback</em> raises an
357
<div class="py-listing"><pre><p class="py-linenumber"> 1
436
</p><span class="py-src-comment">#!/usr/bin/env python</span>
438
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
439
<span class="py-src-comment"># See LICENSE for details.</span>
175
441
<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>
176
442
<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>
178
444
<span class="py-src-string">"""
179
here we have a slightly more involved case. The deferred is called back with a
445
Here we have a slightly more involved case. The deferred is called back with a
180
446
result. the first callback returns a value, the second callback, however
181
447
raises an exception, which is handled by the errback.
182
448
"""</span>
246
512
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
247
513
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
248
514
<span class="py-src-variable">deferredExample</span>()
249
</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><p>And the output: (note, tracebacks will be edited slightly to conserve
515
</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>
517
<p>And the output: (note, tracebacks will be edited slightly to conserve
520
<pre xml:space="preserve">
252
522
got result: success
262
532
File "./deferred_ex1.py", line 32, in failAtHandlingResult
263
533
raise RuntimeError, "whoops! we encountered an error"
264
534
exceptions.RuntimeError: whoops! we encountered an error
265
</pre><p>If your callback raises an exception, the next method to be called will be
266
the next errback in your chain.</p><h3>Exceptions will only be handled by errbacks<a name="auto5"></a></h3><p>If a callback raises an exception the next method to be called will be next
537
<p>If your callback raises an exception, the next method to be called will be
538
the next errback in your chain.</p>
541
<h3>Exceptions will only be handled by errbacks<a name="auto5"/></h3>
543
<p>If a callback raises an exception the next method to be called will be next
267
544
errback in the chain. If the chain is started off with a failure, the first
268
method to be called will be the first errback.</p><div class="py-listing"><pre>
269
<span class="py-src-comment">#!/usr/bin/python
545
method to be called will be the first errback.</p>
547
<div class="py-listing"><pre><p class="py-linenumber"> 1
638
</p><span class="py-src-comment">#!/usr/bin/env python</span>
640
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
641
<span class="py-src-comment"># See LICENSE for details.</span>
271
643
<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>
272
644
<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>
274
646
<span class="py-src-string">"""
275
this example shows an important concept that many deferred newbies
647
This example shows an important concept that many deferred newbies
276
648
(myself included) have trouble understanding.
278
650
when an error occurs in a callback, the first errback after the error
279
651
occurs will be the next method called. (in the next example we'll
280
see what happens in the 'chain' after an errback)
652
see what happens in the 'chain' after an errback).
282
653
"""</span>
284
655
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
307
678
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
308
<span class="py-src-comment"># equivalent to d.callback(result)
310
<span class="py-src-comment"># now, let's make the error happen in the first callback
679
<span class="py-src-comment"># equivalent to d.callback(result)</span>
681
<span class="py-src-comment"># now, let's make the error happen in the first callback</span>
312
683
<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>
313
684
<span class="py-src-keyword">try</span>:
314
685
<span class="py-src-variable">result</span> = <span class="py-src-variable">failAtHandlingResult</span>(<span class="py-src-variable">result</span>)
318
689
<span class="py-src-keyword">pass</span>
321
<span class="py-src-comment"># note: this callback will be skipped because
322
</span> <span class="py-src-comment"># result is a failure
692
<span class="py-src-comment"># note: this callback will be skipped because</span>
693
<span class="py-src-comment"># result is a failure</span>
324
695
<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>
325
696
<span class="py-src-keyword">try</span>:
326
697
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
354
725
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
355
726
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
356
727
<span class="py-src-variable">deferredExample</span>()
357
</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><pre>
728
</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>
730
<pre xml:space="preserve">
359
732
got result: success
360
733
about to raise exception
368
741
File "./deferred_ex2.py", line 35, in failAtHandlingResult
369
742
raise RuntimeError, "whoops! we encountered an error"
370
743
exceptions.RuntimeError: whoops! we encountered an error
371
</pre><p>You can see that our second callback, handleResult was not called because
372
failAtHandlingResult raised an exception</p><h3>Handling an exception and continuing on<a name="auto6"></a></h3><p>In this example, we see an errback handle an exception raised in the
746
<p>You can see that our second callback, handleResult was not called because
747
failAtHandlingResult raised an exception</p>
749
<h3>Handling an exception and continuing on<a name="auto6"/></h3>
751
<p>In this example, we see an errback handle an exception raised in the
373
752
preceeding callback. Take note that it could just as easily been an exception
374
753
from <strong>any other</strong> preceeding method. You'll see that after the
375
754
exception is handled in the errback (i.e. the errback does not return a
376
755
failure or raise an exception) the chain continues on with the next
377
callback.</p><div class="py-listing"><pre>
378
<span class="py-src-comment">#!/usr/bin/python
758
<div class="py-listing"><pre><p class="py-linenumber"> 1
858
</p><span class="py-src-comment">#!/usr/bin/env python</span>
860
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
861
<span class="py-src-comment"># See LICENSE for details.</span>
380
863
<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>
381
864
<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>
383
866
<span class="py-src-string">"""
384
now we see how an errback can handle errors. if an errback
867
Now we see how an errback can handle errors. if an errback
385
868
does not raise an exception, the next callback in the chain
388
870
"""</span>
390
872
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
420
902
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
421
<span class="py-src-comment"># equivalent to d.callback(result)
903
<span class="py-src-comment"># equivalent to d.callback(result)</span>
423
905
<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>
424
906
<span class="py-src-keyword">try</span>:
425
907
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
472
954
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
473
955
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
474
956
<span class="py-src-variable">deferredExample</span>()
475
</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><pre>
957
</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>
959
<pre xml:space="preserve">
477
961
got result: success
499
983
got result: okay, continue on
500
</pre><h2>addBoth: the deferred version of <em>finally</em><a name="auto7"></a></h2><p>Now we see how deferreds do <strong>finally</strong>, with .addBoth. The
986
<h2>addBoth: the deferred version of <em>finally</em><a name="auto7"/></h2>
988
<p>Now we see how deferreds do <strong>finally</strong>, with .addBoth. The
501
989
callback that gets added as addBoth will be called if the result is a failure
502
990
or non-failure. We'll also see in this example, that our doThisNoMatterWhat()
503
991
method follows a common idiom in deferred callbacks by acting as a passthru,
504
992
returning the value that it received to allow processing the chain to
505
continue, but appearing transparent in terms of the result.</p><div class="py-listing"><pre>
506
<span class="py-src-comment">#!/usr/bin/python
993
continue, but appearing transparent in terms of the result.</p>
995
<div class="py-listing"><pre><p class="py-linenumber"> 1
1099
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1101
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1102
<span class="py-src-comment"># See LICENSE for details.</span>
508
1104
<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>
509
1105
<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>
511
1107
<span class="py-src-string">"""
512
now we'll see what happens when you use 'addBoth'
1108
Now we'll see what happens when you use 'addBoth'.
514
1109
"""</span>
516
1111
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
541
1136
<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>,)
542
1137
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tgot argument %r"</span> % (<span class="py-src-variable">arg</span>,)
543
1138
<span class="py-src-keyword">print</span> <span class="py-src-string">"\tdoing something very important"</span>
544
<span class="py-src-comment"># we pass the argument we received to the next phase here
545
</span> <span class="py-src-keyword">return</span> <span class="py-src-variable">arg</span>
1139
<span class="py-src-comment"># we pass the argument we received to the next phase here</span>
1140
<span class="py-src-keyword">return</span> <span class="py-src-variable">arg</span>
549
1144
<span class="py-src-keyword">def</span> <span class="py-src-identifier">behindTheScenes</span>(<span class="py-src-parameter">result</span>):
550
<span class="py-src-comment"># equivalent to d.callback(result)
1145
<span class="py-src-comment"># equivalent to d.callback(result)</span>
552
1147
<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>
553
1148
<span class="py-src-keyword">try</span>:
554
1149
<span class="py-src-variable">result</span> = <span class="py-src-variable">handleResult</span>(<span class="py-src-variable">result</span>)
567
1162
<span class="py-src-keyword">pass</span>
570
<span class="py-src-comment"># ---- this is equivalent to addBoth(doThisNoMatterWhat)
1165
<span class="py-src-comment"># ---- this is equivalent to addBoth(doThisNoMatterWhat)</span>
572
1167
<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>):
573
1168
<span class="py-src-keyword">try</span>:
574
1169
<span class="py-src-variable">result</span> = <span class="py-src-variable">doThisNoMatterWhat</span>(<span class="py-src-variable">result</span>)
605
1200
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
606
1201
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
607
1202
<span class="py-src-variable">deferredExample</span>()
608
</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><pre>
1203
</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>
1205
<pre xml:space="preserve">
610
1207
got result: success
623
1220
File "./deferred_ex4.py", line 32, in failAtHandlingResult
624
1221
raise RuntimeError, "whoops! we encountered an error"
625
1222
exceptions.RuntimeError: whoops! we encountered an error
626
</pre><p>You can see that the errback is called, (and consequently, the failure is
1225
<p>You can see that the errback is called, (and consequently, the failure is
627
1226
trapped). This is because doThisNoMatterWhat method returned the value it
628
received, a failure.</p><h2>addCallbacks: decision making based on previous success or failure<a name="auto8"></a></h2><p>As we've been seeing in the examples, the callback is a pair of
1227
received, a failure.</p>
1229
<h2>addCallbacks: decision making based on previous success or failure<a name="auto8"/></h2>
1231
<p>As we've been seeing in the examples, the callback is a pair of
629
1232
callback/errback. Using addCallback or addErrback is actually a special case
630
1233
where one of the pair is a pass statement. If you want to make a decision
631
1234
based on whether or not the previous result in the chain was a failure or not
632
1235
(which is very rare, but included here for completeness), you use
633
1236
addCallbacks. Note that this is <strong>not</strong> the same thing as an
634
addCallback followed by an addErrback.</p><div class="py-listing"><pre>
635
<span class="py-src-comment">#!/usr/bin/python
1237
addCallback followed by an addErrback.</p>
1240
<div class="py-listing"><pre><p class="py-linenumber"> 1
1376
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1378
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1379
<span class="py-src-comment"># See LICENSE for details.</span>
637
1381
<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>
638
1382
<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>
640
1384
<span class="py-src-string">"""
641
now comes the more nuanced addCallbacks, which allows us to make a
1385
Now comes the more nuanced addCallbacks, which allows us to make a
642
1386
yes/no (branching) decision based on whether the result at a given point is
643
1387
a failure or not.
645
1388
"""</span>
647
1390
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
693
1436
<span class="py-src-keyword">pass</span>
696
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
1439
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
698
1441
<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>
699
1442
<span class="py-src-keyword">try</span>:
700
1443
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
716
1459
<span class="py-src-keyword">pass</span>
719
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
1462
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
721
1464
<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>
722
1465
<span class="py-src-keyword">try</span>:
723
1466
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
765
1508
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
766
1509
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
767
1510
<span class="py-src-variable">deferredExample</span>()
768
</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><pre>
1511
</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>
1513
<pre xml:space="preserve">
770
1515
got result: success
771
1516
about to raise exception
777
1522
wasn't a failure, so we can plow ahead
779
1524
got result: go ahead!
780
</pre><p>Notice that our errback is never called. The noDecision method returns a
1527
<p>Notice that our errback is never called. The noDecision method returns a
781
1528
non-failure so processing continues with the next callback. If we wanted to
782
1529
skip the callback at "- A -" because of the error, but do some kind of
783
1530
processing in response to the error, we would have used a passthru, and
784
returned the failure we received, as we see in this next example: </p><div class="py-listing"><pre>
785
<span class="py-src-comment">#!/usr/bin/python
1531
returned the failure we received, as we see in this next example: </p>
1533
<div class="py-listing"><pre><p class="py-linenumber"> 1
1681
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1683
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1684
<span class="py-src-comment"># See LICENSE for details.</span>
787
1686
<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>
788
1687
<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>
790
1689
<span class="py-src-string">"""
791
now comes the more nuanced addCallbacks, which allows us to make a
1690
Now comes the more nuanced addCallbacks, which allows us to make a
792
1691
yes/no (branching) decision based on whether the result at a given point is
793
1692
a failure or not.
795
1694
here, we return the failure from noDecisionPassthru, the errback argument to
796
the first addCallbacks method invocation, and see what happens
1695
the first addCallbacks method invocation, and see what happens.
798
1696
"""</span>
800
1698
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
851
1749
<span class="py-src-keyword">pass</span>
854
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
1752
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
856
1754
<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>
857
1755
<span class="py-src-keyword">try</span>:
858
1756
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
874
1772
<span class="py-src-keyword">pass</span>
877
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)
1775
<span class="py-src-comment"># this is equivalent to addCallbacks(yesDecision, noDecision)</span>
879
1777
<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>
880
1778
<span class="py-src-keyword">try</span>:
881
1779
<span class="py-src-variable">result</span> = <span class="py-src-variable">yesDecision</span>(<span class="py-src-variable">result</span>)
910
1808
<span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
911
1809
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">failAtHandlingResult</span>)
913
<span class="py-src-comment"># noDecisionPassthru will be called
914
</span> <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>)
1811
<span class="py-src-comment"># noDecisionPassthru 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">noDecisionPassthru</span>)
915
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"># - A -</span>
917
<span class="py-src-comment"># noDecision will be called
918
</span> <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>)
1815
<span class="py-src-comment"># noDecision will be called</span>
1816
<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>)
919
1817
<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>
920
1818
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
927
1825
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
928
1826
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
929
1827
<span class="py-src-variable">deferredExample</span>()
930
</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><pre>
1828
</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>
1830
<pre xml:space="preserve">
932
1832
got result: success
933
1833
about to raise exception
937
1837
*doh*! a failure! quick! damage control!
939
1839
got result: damage control successful!
940
</pre><p>Two things to note here. First, "- A -" was skipped, like we wanted it to,
1842
<p>Two things to note here. First, "- A -" was skipped, like we wanted it to,
941
1843
and the second thing is that after "- A -", noDecision is called, because
942
1844
<strong>it is the next errback that exists in the chain</strong>. It returns a
943
1845
non-failure, so processing continues with the next callback at "- B -", and
944
the errback at the end of the chain is never called </p><h2>Hints, tips, common mistakes, and miscellaney<a name="auto9"></a></h2><h3>The deferred callback chain is stateful<a name="auto10"></a></h3><p>A deferred that has been called back will call it's addCallback and
1846
the errback at the end of the chain is never called </p>
1848
<h2>Hints, tips, common mistakes, and miscellaney<a name="auto9"/></h2>
1850
<h3>The deferred callback chain is stateful<a name="auto10"/></h3>
1852
<p>A deferred that has been called back will call its addCallback and
945
1853
addErrback methods as appropriate in the order they are added, when they are
946
1854
added. So we see in the following example, deferredExample1 and
947
1855
deferredExample2 are equivalent. The first sets up the processing chain
948
1856
beforehand and then executes it, the other executes the chain as it is being
949
constructed. This is because deferreds are <em>stateful</em>. </p><div class="py-listing"><pre>
950
<span class="py-src-comment">#!/usr/bin/python
1857
constructed. This is because deferreds are <em>stateful</em>. </p>
1859
<div class="py-listing"><pre><p class="py-linenumber"> 1
1920
</p><span class="py-src-comment">#!/usr/bin/env python</span>
1922
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
1923
<span class="py-src-comment"># See LICENSE for details.</span>
952
1925
<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>
953
1926
<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>
979
1952
<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>
981
1954
<span class="py-src-keyword">def</span> <span class="py-src-identifier">deferredExample1</span>():
982
<span class="py-src-comment"># this is another common idiom, since all add* methods
983
</span> <span class="py-src-comment"># return the deferred instance, you can just chain your
984
</span> <span class="py-src-comment"># calls to addCallback and addErrback
1955
<span class="py-src-comment"># this is another common idiom, since all add* methods</span>
1956
<span class="py-src-comment"># return the deferred instance, you can just chain your</span>
1957
<span class="py-src-comment"># calls to addCallback and addErrback</span>
986
1959
<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>
987
1960
).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">handleResult</span>
988
1961
).<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">handleFailure</span>)
1004
1977
<span class="py-src-keyword">print</span> <span class="py-src-string">"\n-------------------------------------------------\n"</span>
1005
1978
<span class="py-src-variable">Counter</span>.<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1006
1979
<span class="py-src-variable">deferredExample2</span>()
1007
</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><pre>
1980
</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>
1982
<pre xml:space="preserve">
1009
1984
got result: success
1010
1985
about to raise exception
1033
2008
File "./deferred_ex7.py", line 35, in failAtHandlingResult
1034
2009
raise RuntimeError, "whoops! we encountered an error"
1035
2010
exceptions.RuntimeError: whoops! we encountered an error
1036
</pre><p>This example also shows you the common idiom of chaining calls to
2013
<p>This example also shows you the common idiom of chaining calls to
1037
2014
addCallback and addErrback.
1038
</p><h3>Don't call .callback() on deferreds you didn't create!<a name="auto11"></a></h3><p>It is an error to reinvoke deferreds callback or errback method, therefore
2017
<h3>Don't call .callback() on deferreds you didn't create!<a name="auto11"/></h3>
2019
<p>It is an error to reinvoke deferreds callback or errback method, therefore
1039
2020
if you didn't create a deferred, <strong>do not under any
1040
2021
circumstances</strong> call its callback or errback. doing so will raise
1041
an exception </p><h3>Callbacks can return deferreds<a name="auto12"></a></h3><p>If you need to call a method that returns a deferred within your callback
2024
<h3>Callbacks can return deferreds<a name="auto12"/></h3>
2026
<p>If you need to call a method that returns a deferred within your callback
1042
2027
chain, just return that deferred, and the result of the secondary deferred's
1043
2028
processing chain will become the result that gets passed to the next callback
1044
of the primary deferreds processing chain </p><div class="py-listing"><pre>
1045
<span class="py-src-comment">#!/usr/bin/python
2029
of the primary deferreds processing chain </p>
2031
<div class="py-listing"><pre><p class="py-linenumber"> 1
2097
</p><span class="py-src-comment">#!/usr/bin/env python</span>
2099
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
2100
<span class="py-src-comment"># See LICENSE for details.</span>
1047
2102
<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>
1048
2103
<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>
1050
<span class="py-src-string">"""
1051
"""</span>
1053
2106
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
1054
2107
<span class="py-src-variable">num</span> = <span class="py-src-number">0</span>
1107
2160
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
1108
2161
<span class="py-src-variable">deferredExample</span>()
1109
</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><pre>
2162
</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>
2164
<pre xml:space="preserve">
1111
2166
got result: I hope you'll agree:
1115
2170
adding ' beautiful!' to result
1117
2172
got result: I hope you'll agree: Deferreds are beautiful!
1118
</pre><h2>Conclusion<a name="auto13"></a></h2><p>Deferreds can be confusing, but only because they're so elegant and simple.
2175
<h2>Conclusion<a name="auto13"/></h2>
2177
<p>Deferreds can be confusing, but only because they're so elegant and simple.
1119
2178
There is a lot of logical power that can expressed with a deferred's
1120
2179
processing chain, and once you see what's going on behind the curtain, it's a
1121
lot easier to understand how to make use of what deferreds have to offer.</p></div><p><a href="index.html">Index</a></p><span class="version">Version: 8.2.0</span></body></html>
b'\\ No newline at end of file'
2180
lot easier to understand how to make use of what deferreds have to offer.</p>
2184
<p><a href="index.html">Index</a></p>
2185
<span class="version">Version: 9.0.0</span>
b'\\ No newline at end of file'