~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/core/howto/pb-usage.html

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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">
 
2
  <head>
 
3
<title>Twisted Documentation: Using Perspective Broker</title>
 
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
 
5
  </head>
 
6
 
 
7
  <body bgcolor="white">
 
8
    <h1 class="title">Using Perspective Broker</h1>
 
9
    <div class="toc"><ol><li><a href="#auto0">Basic Example</a></li><li><a href="#auto1">Complete Example</a></li><li><a href="#auto2">References can come back to you</a></li><li><a href="#auto3">References to client-side objects</a></li><li><a href="#auto4">Raising Remote Exceptions</a></li><li><a href="#auto5">Try/Except blocks and Failure.trap </a></li></ol></div>
 
10
    <div class="content">
 
11
<span/>
 
12
 
 
13
<h2>Basic Example<a name="auto0"/></h2>
 
14
 
 
15
<p>The first example to look at is a complete (although somewhat trivial)
 
16
application. It uses <code>PBServerFactory()</code> on the server side, and
 
17
<code>PBClientFactory()</code> on the client side.</p>
 
18
 
 
19
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
20
 2
 
21
 3
 
22
 4
 
23
 5
 
24
 6
 
25
 7
 
26
 8
 
27
 9
 
28
10
 
29
11
 
30
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
31
<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">reactor</span>
 
32
 
 
33
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Echoer</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
34
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_echo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">st</span>):
 
35
        <span class="py-src-keyword">print</span> <span class="py-src-string">'echoing:'</span>, <span class="py-src-variable">st</span>
 
36
        <span class="py-src-keyword">return</span> <span class="py-src-variable">st</span>
 
37
 
 
38
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
 
39
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8789</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">Echoer</span>()))
 
40
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
41
</pre><div class="caption">Source listing - <a href="../examples/pbsimple.py"><span class="filename">../examples/pbsimple.py</span></a></div></div>
 
42
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
43
 2
 
44
 3
 
45
 4
 
46
 5
 
47
 6
 
48
 7
 
49
 8
 
50
 9
 
51
10
 
52
11
 
53
12
 
54
13
 
55
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
56
<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">reactor</span>
 
57
<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">util</span>
 
58
 
 
59
<span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
60
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8789</span>, <span class="py-src-variable">factory</span>)
 
61
<span class="py-src-variable">d</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
 
62
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">object</span>: <span class="py-src-variable">object</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;echo&quot;</span>, <span class="py-src-string">&quot;hello network&quot;</span>))
 
63
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">echo</span>: <span class="py-src-string">'server echoed: '</span>+<span class="py-src-variable">echo</span>)
 
64
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">reason</span>: <span class="py-src-string">'error: '</span>+<span class="py-src-variable">str</span>(<span class="py-src-variable">reason</span>.<span class="py-src-variable">value</span>))
 
65
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">util</span>.<span class="py-src-variable">println</span>)
 
66
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>())
 
67
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
68
</pre><div class="caption">Source listing - <a href="../examples/pbsimpleclient.py"><span class="filename">../examples/pbsimpleclient.py</span></a></div></div>
 
69
 
 
70
<p>First we look at the server. This defines an Echoer class (derived from
 
71
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code>), with a method called
 
72
<code>remote_echo()</code>. 
 
73
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> objects (because of
 
74
their inheritance of 
 
75
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code>, described
 
76
later) can define methods with names of the form <code>remote_*</code>; a
 
77
client which obtains a remote reference to that 
 
78
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> object will be able to
 
79
invoke those methods.</p>
 
80
 
 
81
<p>The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code>-ish object is
 
82
given to a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBServerFactory.html" title="twisted.spread.pb.PBServerFactory">pb.PBServerFactory</a></code><code>()</code>. This is a
 
83
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.Factory.html" title="twisted.internet.protocol.Factory">Factory</a></code> object like
 
84
any other: the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.protocol.Protocol.html" title="twisted.internet.protocol.Protocol">Protocol</a></code> objects it creates for new
 
85
connections know how to speak the PB protocol. The object you give to
 
86
<code>pb.PBServerFactory()</code> becomes the <q>root object</q>, which
 
87
simply makes it available for the client to retrieve. The client may only
 
88
request references to the objects you want to provide it: this helps you
 
89
implement your security model. Because it is so common to export just a
 
90
single object (and because a <code>remote_*</code> method on that one can
 
91
return a reference to any other object you might want to give out), the
 
92
simplest example is one where the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBServerFactory.html" title="twisted.spread.pb.PBServerFactory">PBServerFactory</a></code> is given the root object, and
 
93
the client retrieves it.</p>
 
94
 
 
95
<p>The client side uses
 
96
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBClientFactory.html" title="twisted.spread.pb.PBClientFactory">pb.PBClientFactory</a></code> to make a
 
97
connection to a given port. This is a two-step process involving opening
 
98
a TCP connection to a given host and port and requesting the root object
 
99
using <code>.getRootObject()</code>.</p>
 
100
 
 
101
<p>Because <code>.getRootObject()</code> has to wait until a network
 
102
connection has been made and exchange some data, it may take a while,
 
103
so it returns a Deferred, to which the gotObject() callback is
 
104
attached. (See the documentation on <a href="defer.html" shape="rect">Deferring
 
105
Execution</a> for a complete explanation of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>s). If and when the
 
106
connection succeeds and a reference to the remote root object is
 
107
obtained, this callback is run. The first argument passed to the
 
108
callback is a remote reference to the distant root object.  (you can
 
109
give other arguments to the callback too, see the other parameters for
 
110
<code>.addCallback()</code> and <code>.addCallbacks()</code>).</p>
 
111
 
 
112
<p>The callback does:</p>
 
113
 
 
114
<pre class="python"><p class="py-linenumber">1
 
115
</p><span class="py-src-variable">object</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;echo&quot;</span>, <span class="py-src-string">&quot;hello network&quot;</span>)
 
116
</pre>
 
117
 
 
118
<p>which causes the server's <code>.remote_echo()</code> method to be invoked.
 
119
(running <code>.callRemote(&quot;boom&quot;)</code> would cause
 
120
<code>.remote_boom()</code> to be run, etc). Again because of the delay
 
121
involved, <code>callRemote()</code> returns a 
 
122
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>. Assuming the
 
123
remote method was run without causing an exception (including an attempt to
 
124
invoke an unknown method), the callback attached to that
 
125
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code> will be
 
126
invoked with any objects that were returned by the remote method call.</p>
 
127
 
 
128
<p>In this example, the server's <code>Echoer</code> object has a method
 
129
invoked, <em>exactly</em> as if some code on the server side had done:</p>
 
130
 
 
131
<pre class="python"><p class="py-linenumber">1
 
132
</p><span class="py-src-variable">echoer_object</span>.<span class="py-src-variable">remote_echo</span>(<span class="py-src-string">&quot;hello network&quot;</span>)
 
133
</pre>
 
134
 
 
135
<p>and from the definition of <code>remote_echo()</code> we see that this just
 
136
returns the same string it was given: <q>hello network</q>.</p>
 
137
 
 
138
<p>From the client's point of view, the remote call gets another <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code> object instead of
 
139
that string. <code>callRemote()</code> <em>always</em> returns a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>. This is why PB is
 
140
described as a system for <q>translucent</q> remote method calls instead of
 
141
<q>transparent</q> ones: you cannot pretend that the remote object is really
 
142
local. Trying to do so (as some other RPC mechanisms do, coughCORBAcough)
 
143
breaks down when faced with the asynchronous nature of the network. Using
 
144
Deferreds turns out to be a very clean way to deal with the whole thing.</p>
 
145
 
 
146
<p>The remote reference object (the one given to
 
147
<code>getRootObject()</code>'s success callback) is an instance the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.html" title="twisted.spread.pb.RemoteReference">RemoteReference</a></code> class. This means
 
148
you can use it to invoke methods on the remote object that it refers to. Only
 
149
instances of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.html" title="twisted.spread.pb.RemoteReference">RemoteReference</a></code> are eligible for
 
150
<code>.callRemote()</code>. The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.html" title="twisted.spread.pb.RemoteReference">RemoteReference</a></code> object is the one that lives
 
151
on the remote side (the client, in this case), not the local side (where the
 
152
actual object is defined).</p>
 
153
 
 
154
<p>In our example, the local object is that <code>Echoer()</code> instance,
 
155
which inherits from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code>,
 
156
which inherits from 
 
157
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code>. It is that
 
158
<code>Referenceable</code> class that makes the object eligible to be available
 
159
for remote method calls<a href="#footnote-1" title="There are a few other classes that can bestow this ability, but pb.Referenceable is the easiest to understand; see 'flavors' below for details on the others."><super>1</super></a>. If you have
 
160
an object that is Referenceable, then any client that manages to get a
 
161
reference to it can invoke any <code>remote_*</code> methods they please.</p>
 
162
 
 
163
<div class="note"><strong>Note: </strong>
 
164
<p>The <em>only</em> thing they can do is invoke those
 
165
methods.  In particular, they cannot access attributes. From a security point
 
166
of view, you control what they can do by limiting what the
 
167
<code>remote_*</code> methods can do.</p>
 
168
 
 
169
<p>Also note: the other classes like 
 
170
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">Referenceable</a></code> allow access to
 
171
other methods, in particular <code>perspective_*</code> and <code>view_*</code>
 
172
may be accessed.  Don't write local-only methods with these names, because then
 
173
remote callers will be able to do more than you intended.</p>
 
174
 
 
175
<p>Also also note: the other classes like 
 
176
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code> <em>do</em> allow
 
177
access to attributes, but you control which ones they can see.</p>
 
178
</div>
 
179
 
 
180
<p>You don't have to be a 
 
181
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> to be remotely callable,
 
182
but you do have to be 
 
183
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code>.  (Objects that
 
184
inherit from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code>
 
185
but not from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code> can be
 
186
remotely called, but only 
 
187
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Root.html" title="twisted.spread.pb.Root">pb.Root</a></code>-ish objects can be given
 
188
to the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBServerFactory.html" title="twisted.spread.pb.PBServerFactory">PBServerFactory</a></code>.)</p>
 
189
 
 
190
<h2>Complete Example<a name="auto1"/></h2>
 
191
 
 
192
<p>Here is an example client and server which uses <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">pb.Referenceable</a></code> as a root object and as the
 
193
result of a remotely exposed method.  In each context, methods can be invoked
 
194
on the exposed <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.Referenceable.html" title="twisted.spread.Referenceable">Referenceable</a></code>
 
195
instance.  In this example, the initial root object has a method that returns a
 
196
reference to the second object.</p>
 
197
 
 
198
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
199
 2
 
200
 3
 
201
 4
 
202
 5
 
203
 6
 
204
 7
 
205
 8
 
206
 9
 
207
10
 
208
11
 
209
12
 
210
13
 
211
14
 
212
15
 
213
16
 
214
17
 
215
18
 
216
19
 
217
20
 
218
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
219
 
 
220
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
221
<span class="py-src-comment"># See LICENSE for details.</span>
 
222
 
 
223
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
224
 
 
225
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Two</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Referenceable</span>):
 
226
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_three</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">arg</span>):
 
227
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Two.three was given&quot;</span>, <span class="py-src-variable">arg</span>
 
228
 
 
229
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
230
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_getTwo</span>(<span class="py-src-parameter">self</span>):
 
231
        <span class="py-src-variable">two</span> = <span class="py-src-variable">Two</span>()
 
232
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;returning a Two called&quot;</span>, <span class="py-src-variable">two</span>
 
233
        <span class="py-src-keyword">return</span> <span class="py-src-variable">two</span>
 
234
 
 
235
<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">reactor</span>
 
236
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">One</span>()))
 
237
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
238
</pre><div class="caption">Source listing - <a href="listings/pb/pb1server.py"><span class="filename">listings/pb/pb1server.py</span></a></div></div>
 
239
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
240
 2
 
241
 3
 
242
 4
 
243
 5
 
244
 6
 
245
 7
 
246
 8
 
247
 9
 
248
10
 
249
11
 
250
12
 
251
13
 
252
14
 
253
15
 
254
16
 
255
17
 
256
18
 
257
19
 
258
20
 
259
21
 
260
22
 
261
23
 
262
24
 
263
25
 
264
26
 
265
27
 
266
28
 
267
29
 
268
30
 
269
31
 
270
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
271
 
 
272
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
273
<span class="py-src-comment"># See LICENSE for details.</span>
 
274
 
 
275
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
276
<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">reactor</span>
 
277
 
 
278
<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
 
279
    <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
280
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
 
281
    <span class="py-src-variable">def1</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
 
282
    <span class="py-src-variable">def1</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">got_obj1</span>, <span class="py-src-variable">err_obj1</span>)
 
283
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
284
 
 
285
<span class="py-src-keyword">def</span> <span class="py-src-identifier">err_obj1</span>(<span class="py-src-parameter">reason</span>):
 
286
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;error getting first object&quot;</span>, <span class="py-src-variable">reason</span>
 
287
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
 
288
 
 
289
<span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj1</span>(<span class="py-src-parameter">obj1</span>):
 
290
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got first object:&quot;</span>, <span class="py-src-variable">obj1</span>
 
291
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;asking it to getTwo&quot;</span>
 
292
    <span class="py-src-variable">def2</span> = <span class="py-src-variable">obj1</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;getTwo&quot;</span>)
 
293
    <span class="py-src-variable">def2</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">got_obj2</span>)
 
294
 
 
295
<span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj2</span>(<span class="py-src-parameter">obj2</span>):
 
296
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got second object:&quot;</span>, <span class="py-src-variable">obj2</span>
 
297
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;telling it to do three(12)&quot;</span>
 
298
    <span class="py-src-variable">obj2</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;three&quot;</span>, <span class="py-src-number">12</span>)
 
299
 
 
300
<span class="py-src-variable">main</span>()
 
301
</pre><div class="caption">Source listing - <a href="listings/pb/pb1client.py"><span class="filename">listings/pb/pb1client.py</span></a></div></div>
 
302
 
 
303
<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBClientFactory.getRootObject.html" title="twisted.spread.pb.PBClientFactory.getRootObject">pb.PBClientFactory.getRootObject</a></code> will
 
304
handle all the details of waiting for the creation of a connection.
 
305
It returns a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>, which will have its
 
306
callback called when the reactor connects to the remote server and
 
307
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBClientFactory.html" title="twisted.spread.pb.PBClientFactory">pb.PBClientFactory</a></code> gets the
 
308
root, and have its <code class="python">errback</code> called when the
 
309
object-connection fails for any reason, whether it was host lookup
 
310
failure, connection refusal, or some server-side error.
 
311
</p>
 
312
 
 
313
<p>The root object has a method called <code>remote_getTwo</code>, which
 
314
returns the <code>Two()</code> instance. On the client end, the callback gets
 
315
a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.html" title="twisted.spread.pb.RemoteReference">RemoteReference</a></code> to that
 
316
instance. The client can then invoke two's <code>.remote_three()</code>
 
317
method.</p>
 
318
 
 
319
<p><code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.html" title="twisted.spread.pb.RemoteReference">RemoteReference</a></code>
 
320
objects have one method which is their purpose for being: <code class="python">callRemote</code>.  This method allows you to call a
 
321
remote method on the object being referred to by the Reference.  <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.RemoteReference.callRemote.html" title="twisted.spread.pb.RemoteReference.callRemote">RemoteReference.callRemote</a></code>, like <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBClientFactory.getRootObject.html" title="twisted.spread.pb.PBClientFactory.getRootObject">pb.PBClientFactory.getRootObject</a></code>, returns
 
322
a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>.
 
323
When a response to the method-call being sent arrives, the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>'s <code class="python">callback</code> or <code class="python">errback</code>
 
324
will be made, depending on whether an error occurred in processing the
 
325
method call.</p>
 
326
 
 
327
<p>You can use this technique to provide access to arbitrary sets of objects.
 
328
Just remember that any object that might get passed <q>over the wire</q> must
 
329
inherit from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Referenceable.html" title="twisted.spread.pb.Referenceable">Referenceable</a></code>
 
330
(or one of the other flavors). If you try to pass a non-Referenceable object
 
331
(say, by returning one from a <code>remote_*</code> method), you'll get an
 
332
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.jelly.InsecureJelly.html" title="twisted.spread.jelly.InsecureJelly">InsecureJelly</a></code>
 
333
exception<a href="#footnote-2" title="This can be overridden, by subclassing one of the Serializable flavors and defining custom serialization code for your class. See Passing Complex Types for details."><super>2</super></a>.</p>
 
334
 
 
335
 
 
336
<h2>References can come back to you<a name="auto2"/></h2>
 
337
 
 
338
<p>If your server gives a reference to a client, and then that client gives
 
339
the reference back to the server, the server will wind up with the same
 
340
object it gave out originally. The serialization layer watches for returning
 
341
reference identifiers and turns them into actual objects. You need to stay
 
342
aware of where the object lives: if it is on your side, you do actual method
 
343
calls. If it is on the other side, you do 
 
344
<code>.callRemote()</code><a href="#footnote-3" title="The binary nature of this local vs. remote scheme works because you cannot give RemoteReferences to a third party. If you could, then your object A could go to B, B could give it to C, C might give it back to you, and you would be hard pressed to tell if the object lived in C's memory space, in B's, or if it was really your own object, tarnished and sullied after being handed down like a really ugly picture that your great aunt owned and which nobody wants but which nobody can bear to throw out. Ok, not really like that, but you get the idea."><super>3</super></a>.</p>
 
345
 
 
346
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
347
 2
 
348
 3
 
349
 4
 
350
 5
 
351
 6
 
352
 7
 
353
 8
 
354
 9
 
355
10
 
356
11
 
357
12
 
358
13
 
359
14
 
360
15
 
361
16
 
362
17
 
363
18
 
364
19
 
365
20
 
366
21
 
367
22
 
368
23
 
369
24
 
370
25
 
371
26
 
372
27
 
373
28
 
374
29
 
375
30
 
376
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
377
 
 
378
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
379
<span class="py-src-comment"># See LICENSE for details.</span>
 
380
 
 
381
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
382
<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">reactor</span>
 
383
 
 
384
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Two</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Referenceable</span>):
 
385
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_print</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">arg</span>):
 
386
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;two.print was given&quot;</span>, <span class="py-src-variable">arg</span>
 
387
 
 
388
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
389
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">two</span>):
 
390
        <span class="py-src-comment">#pb.Root.__init__(self)   # pb.Root doesn't implement __init__</span>
 
391
        <span class="py-src-variable">self</span>.<span class="py-src-variable">two</span> = <span class="py-src-variable">two</span>
 
392
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_getTwo</span>(<span class="py-src-parameter">self</span>):
 
393
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;One.getTwo(), returning my two called&quot;</span>, <span class="py-src-variable">two</span>
 
394
        <span class="py-src-keyword">return</span> <span class="py-src-variable">two</span>
 
395
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_checkTwo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">newtwo</span>):
 
396
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;One.checkTwo(): comparing my two&quot;</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">two</span>
 
397
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;One.checkTwo(): against your two&quot;</span>, <span class="py-src-variable">newtwo</span>
 
398
        <span class="py-src-keyword">if</span> <span class="py-src-variable">two</span> == <span class="py-src-variable">newtwo</span>:
 
399
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;One.checkTwo(): our twos are the same&quot;</span>
 
400
 
 
401
 
 
402
<span class="py-src-variable">two</span> = <span class="py-src-variable">Two</span>()
 
403
<span class="py-src-variable">root_obj</span> = <span class="py-src-variable">One</span>(<span class="py-src-variable">two</span>)
 
404
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">root_obj</span>))
 
405
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
406
</pre><div class="caption">Source listing - <a href="listings/pb/pb2server.py"><span class="filename">listings/pb/pb2server.py</span></a></div></div>
 
407
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
408
 2
 
409
 3
 
410
 4
 
411
 5
 
412
 6
 
413
 7
 
414
 8
 
415
 9
 
416
10
 
417
11
 
418
12
 
419
13
 
420
14
 
421
15
 
422
16
 
423
17
 
424
18
 
425
19
 
426
20
 
427
21
 
428
22
 
429
23
 
430
24
 
431
25
 
432
26
 
433
27
 
434
28
 
435
29
 
436
30
 
437
31
 
438
32
 
439
33
 
440
34
 
441
35
 
442
36
 
443
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
444
 
 
445
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
446
<span class="py-src-comment"># See LICENSE for details.</span>
 
447
 
 
448
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
449
<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">reactor</span>
 
450
 
 
451
<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
 
452
    <span class="py-src-variable">foo</span> = <span class="py-src-variable">Foo</span>()
 
453
    <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
454
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
 
455
    <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>().<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">foo</span>.<span class="py-src-variable">step1</span>)
 
456
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
457
 
 
458
<span class="py-src-comment"># keeping globals around is starting to get ugly, so we use a simple class</span>
 
459
<span class="py-src-comment"># instead. Instead of hooking one function to the next, we hook one method</span>
 
460
<span class="py-src-comment"># to the next.</span>
 
461
 
 
462
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Foo</span>:
 
463
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
 
464
        <span class="py-src-variable">self</span>.<span class="py-src-variable">oneRef</span> = <span class="py-src-variable">None</span>
 
465
 
 
466
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">step1</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">obj</span>):
 
467
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got one object:&quot;</span>, <span class="py-src-variable">obj</span>
 
468
        <span class="py-src-variable">self</span>.<span class="py-src-variable">oneRef</span> = <span class="py-src-variable">obj</span>
 
469
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;asking it to getTwo&quot;</span>
 
470
        <span class="py-src-variable">self</span>.<span class="py-src-variable">oneRef</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;getTwo&quot;</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">step2</span>)
 
471
 
 
472
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">step2</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">two</span>):
 
473
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got two object:&quot;</span>, <span class="py-src-variable">two</span>
 
474
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;giving it back to one&quot;</span>
 
475
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;one is&quot;</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">oneRef</span>
 
476
        <span class="py-src-variable">self</span>.<span class="py-src-variable">oneRef</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;checkTwo&quot;</span>, <span class="py-src-variable">two</span>)
 
477
 
 
478
<span class="py-src-variable">main</span>()
 
479
</pre><div class="caption">Source listing - <a href="listings/pb/pb2client.py"><span class="filename">listings/pb/pb2client.py</span></a></div></div>
 
480
 
 
481
<p>The server gives a <code>Two()</code> instance to the client, who then
 
482
returns the reference back to the server. The server compares the <q>two</q>
 
483
given with the <q>two</q> received and shows that they are the same, and that
 
484
both are real objects instead of remote references.</p>
 
485
 
 
486
<p>A few other techniques are demonstrated in <code>pb2client.py</code>. One
 
487
is that the callbacks are are added with <code>.addCallback</code> instead
 
488
of <code>.addCallbacks</code>. As you can tell from the <a href="defer.html" shape="rect">Deferred</a> documentation, <code>.addCallback</code> is a
 
489
simplified form which only adds a success callback. The other is that to
 
490
keep track of state from one callback to the next (the remote reference to
 
491
the main One() object), we create a simple class, store the reference in an
 
492
instance thereof, and point the callbacks at a sequence of bound methods.
 
493
This is a convenient way to encapsulate a state machine. Each response kicks
 
494
off the next method, and any data that needs to be carried from one state to
 
495
the next can simply be saved as an attribute of the object.</p>
 
496
 
 
497
<p>Remember that the client can give you back any remote reference you've
 
498
given them. Don't base your zillion-dollar stock-trading clearinghouse
 
499
server on the idea that you trust the client to give you back the right
 
500
reference. The security model inherent in PB means that they can <em>only</em>
 
501
give you back a reference that you've given them for the current connection
 
502
(not one you've given to someone else instead, nor one you gave them last
 
503
time before the TCP session went down, nor one you haven't yet given to the
 
504
client), but just like with URLs and HTTP cookies, the particular reference
 
505
they give you is entirely under their control.</p>
 
506
 
 
507
 
 
508
<h2>References to client-side objects<a name="auto3"/></h2>
 
509
 
 
510
<p>Anything that's Referenceable can get passed across the wire, <em>in
 
511
either direction</em>. The <q>client</q> can give a reference to the
 
512
<q>server</q>, and then the server can use .callRemote() to invoke methods on
 
513
the client end. This fuzzes the distinction between <q>client</q> and
 
514
<q>server</q>: the only real difference is who initiates the original TCP
 
515
connection; after that it's all symmetric.</p>
 
516
 
 
517
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
518
 2
 
519
 3
 
520
 4
 
521
 5
 
522
 6
 
523
 7
 
524
 8
 
525
 9
 
526
10
 
527
11
 
528
12
 
529
13
 
530
14
 
531
15
 
532
16
 
533
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
534
 
 
535
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
536
<span class="py-src-comment"># See LICENSE for details.</span>
 
537
 
 
538
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
539
<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">reactor</span>
 
540
 
 
541
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
542
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_takeTwo</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">two</span>):
 
543
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;received a Two called&quot;</span>, <span class="py-src-variable">two</span>
 
544
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;telling it to print(12)&quot;</span>
 
545
        <span class="py-src-variable">two</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;print&quot;</span>, <span class="py-src-number">12</span>)
 
546
 
 
547
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">One</span>()))
 
548
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
549
</pre><div class="caption">Source listing - <a href="listings/pb/pb3server.py"><span class="filename">listings/pb/pb3server.py</span></a></div></div>
 
550
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
551
 2
 
552
 3
 
553
 4
 
554
 5
 
555
 6
 
556
 7
 
557
 8
 
558
 9
 
559
10
 
560
11
 
561
12
 
562
13
 
563
14
 
564
15
 
565
16
 
566
17
 
567
18
 
568
19
 
569
20
 
570
21
 
571
22
 
572
23
 
573
24
 
574
25
 
575
26
 
576
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
577
 
 
578
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
579
<span class="py-src-comment"># See LICENSE for details.</span>
 
580
 
 
581
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
582
<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">reactor</span>
 
583
 
 
584
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Two</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Referenceable</span>):
 
585
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_print</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">arg</span>):
 
586
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;Two.print() called with&quot;</span>, <span class="py-src-variable">arg</span>
 
587
 
 
588
<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
 
589
    <span class="py-src-variable">two</span> = <span class="py-src-variable">Two</span>()
 
590
    <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
591
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
 
592
    <span class="py-src-variable">def1</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
 
593
    <span class="py-src-variable">def1</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">got_obj</span>, <span class="py-src-variable">two</span>) <span class="py-src-comment"># hands our 'two' to the callback</span>
 
594
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
595
 
 
596
<span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj</span>(<span class="py-src-parameter">obj</span>, <span class="py-src-parameter">two</span>):
 
597
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got One:&quot;</span>, <span class="py-src-variable">obj</span>
 
598
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;giving it our two&quot;</span>
 
599
    <span class="py-src-variable">obj</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;takeTwo&quot;</span>, <span class="py-src-variable">two</span>)
 
600
 
 
601
<span class="py-src-variable">main</span>()
 
602
</pre><div class="caption">Source listing - <a href="listings/pb/pb3client.py"><span class="filename">listings/pb/pb3client.py</span></a></div></div>
 
603
 
 
604
<p>In this example, the client gives a reference to its own object to the
 
605
server. The server then invokes a remote method on the client-side
 
606
object.</p>
 
607
 
 
608
 
 
609
<h2>Raising Remote Exceptions<a name="auto4"/></h2>
 
610
 
 
611
<p>Everything so far has covered what happens when things go right. What
 
612
about when they go wrong? The Python Way is to raise an exception of some
 
613
sort. The Twisted Way is the same.</p>
 
614
 
 
615
<p>The only special thing you do is to define your <code>Exception</code>
 
616
subclass by deriving it from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Error.html" title="twisted.spread.pb.Error">pb.Error</a></code>. When any remotely-invokable method
 
617
(like <code>remote_*</code> or <code>perspective_*</code>) raises a
 
618
<code>pb.Error</code>-derived exception, a serialized form of that Exception
 
619
object will be sent back over the wire<a href="#footnote-4" title="To be precise, the Failure will be sent if any exception is raised, not just pb.Error-derived ones. But the server will print ugly error messages if you raise ones that aren't derived from pb.Error."><super>4</super></a>. The other side (which
 
620
did <code>callRemote</code>) will have the <q><code>errback</code></q>
 
621
callback run with a <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> object that contains a copy of
 
622
the exception object. This <code>Failure</code> object can be queried to
 
623
retrieve the error message and a stack traceback.</p>
 
624
 
 
625
<p><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> is a
 
626
special class, defined in <code>twisted/python/failure.py</code>, created to
 
627
make it easier to handle asynchronous exceptions. Just as exception handlers
 
628
can be nested, <code>errback</code> functions can be chained. If one errback
 
629
can't handle the particular type of failure, it can be <q>passed along</q> to a
 
630
errback handler further down the chain.</p>
 
631
 
 
632
<p>For simple purposes, think of the <code>Failure</code> as just a container
 
633
for remotely-thrown <code>Exception</code> objects. To extract the string that
 
634
was put into the exception, use its <code>.getErrorMessage()</code> method.
 
635
To get the type of the exception (as a string), look at its
 
636
<code>.type</code> attribute. The stack traceback is available too. The
 
637
intent is to let the errback function get just as much information about the
 
638
exception as Python's normal <code>try:</code> clauses do, even though the
 
639
exception occurred in somebody else's memory space at some unknown time in
 
640
the past.</p>
 
641
 
 
642
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
643
 2
 
644
 3
 
645
 4
 
646
 5
 
647
 6
 
648
 7
 
649
 8
 
650
 9
 
651
10
 
652
11
 
653
12
 
654
13
 
655
14
 
656
15
 
657
16
 
658
17
 
659
18
 
660
19
 
661
20
 
662
21
 
663
22
 
664
23
 
665
24
 
666
25
 
667
26
 
668
27
 
669
28
 
670
29
 
671
30
 
672
31
 
673
32
 
674
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
675
 
 
676
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
677
<span class="py-src-comment"># See LICENSE for details.</span>
 
678
 
 
679
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
680
<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">reactor</span>
 
681
 
 
682
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyError</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Error</span>):
 
683
    <span class="py-src-string">&quot;&quot;&quot;This is an Expected Exception. Something bad happened.&quot;&quot;&quot;</span>
 
684
    <span class="py-src-keyword">pass</span>
 
685
 
 
686
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyError2</span>(<span class="py-src-parameter">Exception</span>):
 
687
    <span class="py-src-string">&quot;&quot;&quot;This is an Unexpected Exception. Something really bad happened.&quot;&quot;&quot;</span>
 
688
    <span class="py-src-keyword">pass</span>
 
689
 
 
690
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
691
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_broken</span>(<span class="py-src-parameter">self</span>):
 
692
        <span class="py-src-variable">msg</span> = <span class="py-src-string">&quot;fall down go boom&quot;</span>
 
693
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;raising a MyError exception with data '%s'&quot;</span> % <span class="py-src-variable">msg</span>
 
694
        <span class="py-src-keyword">raise</span> <span class="py-src-variable">MyError</span>(<span class="py-src-variable">msg</span>)
 
695
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_broken2</span>(<span class="py-src-parameter">self</span>):
 
696
        <span class="py-src-variable">msg</span> = <span class="py-src-string">&quot;hadda owie&quot;</span>
 
697
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;raising a MyError2 exception with data '%s'&quot;</span> % <span class="py-src-variable">msg</span>
 
698
        <span class="py-src-keyword">raise</span> <span class="py-src-variable">MyError2</span>(<span class="py-src-variable">msg</span>)
 
699
 
 
700
<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
 
701
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">One</span>()))
 
702
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
703
 
 
704
<span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">'__main__'</span>:
 
705
    <span class="py-src-variable">main</span>()
 
706
</pre><div class="caption">Source listing - <a href="listings/pb/exc_server.py"><span class="filename">listings/pb/exc_server.py</span></a></div></div>
 
707
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
708
 2
 
709
 3
 
710
 4
 
711
 5
 
712
 6
 
713
 7
 
714
 8
 
715
 9
 
716
10
 
717
11
 
718
12
 
719
13
 
720
14
 
721
15
 
722
16
 
723
17
 
724
18
 
725
19
 
726
20
 
727
21
 
728
22
 
729
23
 
730
24
 
731
25
 
732
26
 
733
27
 
734
28
 
735
29
 
736
30
 
737
31
 
738
32
 
739
33
 
740
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
741
 
 
742
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
743
<span class="py-src-comment"># See LICENSE for details.</span>
 
744
 
 
745
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
746
<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">reactor</span>
 
747
 
 
748
<span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
 
749
    <span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
750
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
 
751
    <span class="py-src-variable">d</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
 
752
    <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">got_obj</span>)
 
753
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
754
 
 
755
<span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj</span>(<span class="py-src-parameter">obj</span>):
 
756
    <span class="py-src-comment"># change &quot;broken&quot; into &quot;broken2&quot; to demonstrate an unhandled exception</span>
 
757
    <span class="py-src-variable">d2</span> = <span class="py-src-variable">obj</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;broken&quot;</span>)
 
758
    <span class="py-src-variable">d2</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">working</span>)
 
759
    <span class="py-src-variable">d2</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">broken</span>)
 
760
 
 
761
<span class="py-src-keyword">def</span> <span class="py-src-identifier">working</span>():
 
762
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;erm, it wasn't *supposed* to work..&quot;</span>
 
763
 
 
764
<span class="py-src-keyword">def</span> <span class="py-src-identifier">broken</span>(<span class="py-src-parameter">reason</span>):
 
765
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;got remote Exception&quot;</span>
 
766
    <span class="py-src-comment"># reason should be a Failure (or subclass) holding the MyError exception</span>
 
767
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; .__class__ =&quot;</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">__class__</span>
 
768
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; .getErrorMessage() =&quot;</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">getErrorMessage</span>()
 
769
    <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; .type =&quot;</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">type</span>
 
770
    <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
 
771
 
 
772
<span class="py-src-variable">main</span>()
 
773
</pre><div class="caption">Source listing - <a href="listings/pb/exc_client.py"><span class="filename">listings/pb/exc_client.py</span></a></div></div>
 
774
 
 
775
<pre class="shell" xml:space="preserve">
 
776
% ./exc_client.py 
 
777
got remote Exception
 
778
 .__class__ = twisted.spread.pb.CopiedFailure
 
779
 .getErrorMessage() = fall down go boom
 
780
 .type = __main__.MyError
 
781
Main loop terminated.
 
782
</pre>
 
783
 
 
784
<p>Oh, and what happens if you raise some other kind of exception? Something
 
785
that <em>isn't</em> subclassed from <code>pb.Error</code>? Well, those are
 
786
called <q>unexpected exceptions</q>, which make Twisted think that something
 
787
has <em>really</em> gone wrong. These will raise an exception on the
 
788
<em>server</em> side. This won't break the connection (the exception is
 
789
trapped, just like most exceptions that occur in response to network
 
790
traffic), but it will print out an unsightly stack trace on the server's
 
791
stderr with a message that says <q>Peer Will Receive PB Traceback</q>, just
 
792
as if the exception had happened outside a remotely-invokable method. (This
 
793
message will go the current log target, if <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.log.startLogging.html" title="twisted.python.log.startLogging">log.startLogging</a></code> was used to redirect it). The
 
794
client will get the same <code>Failure</code> object in either case, but
 
795
subclassing your exception from <code>pb.Error</code> is the way to tell
 
796
Twisted that you expect this sort of exception, and that it is ok to just
 
797
let the client handle it instead of also asking the server to complain. Look
 
798
at <code>exc_client.py</code> and change it to invoke <code>broken2()</code>
 
799
instead of <code>broken()</code> to see the change in the server's
 
800
behavior.</p>
 
801
 
 
802
<p>If you don't add an <code>errback</code> function to the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.defer.Deferred.html" title="twisted.internet.defer.Deferred">Deferred</a></code>, then a remote
 
803
exception will still send a <code>Failure</code> object back over, but it
 
804
will get lodged in the <code>Deferred</code> with nowhere to go. When that
 
805
<code>Deferred</code> finally goes out of scope, the side that did
 
806
<code>callRemote</code> will emit a message about an <q>Unhandled error in
 
807
Deferred</q>, along with an ugly stack trace. It can't raise an exception at
 
808
that point (after all, the <code>callRemote</code> that triggered the
 
809
problem is long gone), but it will emit a traceback. So be a good programmer
 
810
and <em>always add <code>errback</code> handlers</em>, even if they are just
 
811
calls to <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.log.err.html" title="twisted.python.log.err">log.err</a></code>.</p>
 
812
 
 
813
<h2>Try/Except blocks and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.failure.Failure.trap.html" title="twisted.python.failure.Failure.trap">Failure.trap</a></code> <a name="auto5"/></h2>
 
814
 
 
815
<p>To implement the equivalent of the Python try/except blocks (which can
 
816
trap particular kinds of exceptions and pass others <q>up</q> to
 
817
higher-level <code>try/except</code> blocks), you can use the
 
818
<code>.trap()</code> method in conjunction with multiple
 
819
<code>errback</code> handlers on the <code>Deferred</code>. Re-raising an
 
820
exception in an <code>errback</code> handler serves to pass that new
 
821
exception to the next handler in the chain. The <code>trap</code> method is
 
822
given a list of exceptions to look for, and will re-raise anything that
 
823
isn't on the list. Instead of passing unhandled exceptions <q>up</q> to an
 
824
enclosing <code>try</code> block, this has the effect of passing the
 
825
exception <q>off</q> to later <code>errback</code> handlers on the same
 
826
<code>Deferred</code>. The <code>trap</code> calls are used in chained
 
827
errbacks to test for each kind of exception in sequence. </p>
 
828
 
 
829
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
830
 2
 
831
 3
 
832
 4
 
833
 5
 
834
 6
 
835
 7
 
836
 8
 
837
 9
 
838
10
 
839
11
 
840
12
 
841
13
 
842
14
 
843
15
 
844
16
 
845
17
 
846
18
 
847
19
 
848
20
 
849
21
 
850
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
851
 
 
852
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
853
<span class="py-src-comment"># See LICENSE for details.</span>
 
854
 
 
855
<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">reactor</span>
 
856
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
 
857
 
 
858
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyException</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Error</span>):
 
859
    <span class="py-src-keyword">pass</span>
 
860
 
 
861
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Root</span>):
 
862
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_fooMethod</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">arg</span>):
 
863
        <span class="py-src-keyword">if</span> <span class="py-src-variable">arg</span> == <span class="py-src-string">&quot;panic!&quot;</span>:
 
864
            <span class="py-src-keyword">raise</span> <span class="py-src-variable">MyException</span>
 
865
        <span class="py-src-keyword">return</span> <span class="py-src-string">&quot;response&quot;</span>
 
866
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">remote_shutdown</span>(<span class="py-src-parameter">self</span>):
 
867
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
 
868
 
 
869
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">8800</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">One</span>()))
 
870
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
871
</pre><div class="caption">Source listing - <a href="listings/pb/trap_server.py"><span class="filename">listings/pb/trap_server.py</span></a></div></div>
 
872
<div class="py-listing"><pre><p class="py-linenumber"> 1
 
873
 2
 
874
 3
 
875
 4
 
876
 5
 
877
 6
 
878
 7
 
879
 8
 
880
 9
 
881
10
 
882
11
 
883
12
 
884
13
 
885
14
 
886
15
 
887
16
 
888
17
 
889
18
 
890
19
 
891
20
 
892
21
 
893
22
 
894
23
 
895
24
 
896
25
 
897
26
 
898
27
 
899
28
 
900
29
 
901
30
 
902
31
 
903
32
 
904
33
 
905
34
 
906
35
 
907
36
 
908
37
 
909
38
 
910
39
 
911
40
 
912
41
 
913
42
 
914
43
 
915
44
 
916
45
 
917
46
 
918
47
 
919
48
 
920
49
 
921
50
 
922
51
 
923
52
 
924
53
 
925
54
 
926
55
 
927
56
 
928
57
 
929
58
 
930
59
 
931
60
 
932
61
 
933
62
 
934
63
 
935
64
 
936
65
 
937
66
 
938
67
 
939
68
 
940
69
 
941
70
 
942
71
 
943
72
 
944
73
 
945
74
 
946
75
 
947
76
 
948
77
 
949
78
 
950
79
 
951
80
 
952
81
 
953
82
 
954
83
 
955
84
 
956
85
 
957
86
 
958
87
 
959
88
 
960
</p><span class="py-src-comment">#!/usr/bin/env python</span>
 
961
 
 
962
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
 
963
<span class="py-src-comment"># See LICENSE for details.</span>
 
964
 
 
965
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>, <span class="py-src-variable">jelly</span>
 
966
<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">log</span>
 
967
<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">reactor</span>
 
968
 
 
969
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyException</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Error</span>): <span class="py-src-keyword">pass</span>
 
970
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyOtherException</span>(<span class="py-src-parameter">pb</span>.<span class="py-src-parameter">Error</span>): <span class="py-src-keyword">pass</span>
 
971
 
 
972
<span class="py-src-keyword">class</span> <span class="py-src-identifier">ScaryObject</span>:
 
973
    <span class="py-src-comment"># not safe for serialization</span>
 
974
    <span class="py-src-keyword">pass</span>
 
975
 
 
976
<span class="py-src-keyword">def</span> <span class="py-src-identifier">worksLike</span>(<span class="py-src-parameter">obj</span>):
 
977
    <span class="py-src-comment"># the callback/errback sequence in class One works just like an</span>
 
978
    <span class="py-src-comment"># asynchronous version of the following:</span>
 
979
    <span class="py-src-keyword">try</span>:
 
980
        <span class="py-src-variable">response</span> = <span class="py-src-variable">obj</span>.<span class="py-src-variable">callMethod</span>(<span class="py-src-variable">name</span>, <span class="py-src-variable">arg</span>)
 
981
    <span class="py-src-keyword">except</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">DeadReferenceError</span>:
 
982
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; stale reference: the client disconnected or crashed&quot;</span>
 
983
    <span class="py-src-keyword">except</span> <span class="py-src-variable">jelly</span>.<span class="py-src-variable">InsecureJelly</span>:
 
984
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; InsecureJelly: you tried to send something unsafe to them&quot;</span>
 
985
    <span class="py-src-keyword">except</span> (<span class="py-src-variable">MyException</span>, <span class="py-src-variable">MyOtherException</span>):
 
986
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; remote raised a MyException&quot;</span> <span class="py-src-comment"># or MyOtherException</span>
 
987
    <span class="py-src-keyword">except</span>:
 
988
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; something else happened&quot;</span>
 
989
    <span class="py-src-keyword">else</span>:
 
990
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; method successful, response:&quot;</span>, <span class="py-src-variable">response</span>
 
991
 
 
992
<span class="py-src-keyword">class</span> <span class="py-src-identifier">One</span>:
 
993
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">worked</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">response</span>):
 
994
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; method successful, response:&quot;</span>, <span class="py-src-variable">response</span>
 
995
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">check_InsecureJelly</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>):
 
996
        <span class="py-src-variable">failure</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">jelly</span>.<span class="py-src-variable">InsecureJelly</span>)
 
997
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; InsecureJelly: you tried to send something unsafe to them&quot;</span>
 
998
        <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span>
 
999
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">check_MyException</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>):
 
1000
        <span class="py-src-variable">which</span> = <span class="py-src-variable">failure</span>.<span class="py-src-variable">trap</span>(<span class="py-src-variable">MyException</span>, <span class="py-src-variable">MyOtherException</span>)
 
1001
        <span class="py-src-keyword">if</span> <span class="py-src-variable">which</span> == <span class="py-src-variable">MyException</span>:
 
1002
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; remote raised a MyException&quot;</span>
 
1003
        <span class="py-src-keyword">else</span>:
 
1004
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; remote raised a MyOtherException&quot;</span>
 
1005
        <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span>
 
1006
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">catch_everythingElse</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">failure</span>):
 
1007
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; something else happened&quot;</span>
 
1008
        <span class="py-src-variable">log</span>.<span class="py-src-variable">err</span>(<span class="py-src-variable">failure</span>)
 
1009
        <span class="py-src-keyword">return</span> <span class="py-src-variable">None</span>
 
1010
 
 
1011
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">doCall</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">explanation</span>, <span class="py-src-parameter">arg</span>):
 
1012
        <span class="py-src-keyword">print</span> <span class="py-src-variable">explanation</span>
 
1013
        <span class="py-src-keyword">try</span>:
 
1014
            <span class="py-src-variable">deferred</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;fooMethod&quot;</span>, <span class="py-src-variable">arg</span>)
 
1015
            <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">worked</span>)
 
1016
            <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">check_InsecureJelly</span>)
 
1017
            <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">check_MyException</span>)
 
1018
            <span class="py-src-variable">deferred</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">catch_everythingElse</span>)
 
1019
        <span class="py-src-keyword">except</span> <span class="py-src-variable">pb</span>.<span class="py-src-variable">DeadReferenceError</span>:
 
1020
            <span class="py-src-keyword">print</span> <span class="py-src-string">&quot; stale reference: the client disconnected or crashed&quot;</span>
 
1021
 
 
1022
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">callOne</span>(<span class="py-src-parameter">self</span>):
 
1023
        <span class="py-src-variable">self</span>.<span class="py-src-variable">doCall</span>(<span class="py-src-string">&quot;callOne: call with safe object&quot;</span>, <span class="py-src-string">&quot;safe string&quot;</span>)
 
1024
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">callTwo</span>(<span class="py-src-parameter">self</span>):
 
1025
        <span class="py-src-variable">self</span>.<span class="py-src-variable">doCall</span>(<span class="py-src-string">&quot;callTwo: call with dangerous object&quot;</span>, <span class="py-src-variable">ScaryObject</span>())
 
1026
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">callThree</span>(<span class="py-src-parameter">self</span>):
 
1027
        <span class="py-src-variable">self</span>.<span class="py-src-variable">doCall</span>(<span class="py-src-string">&quot;callThree: call that raises remote exception&quot;</span>, <span class="py-src-string">&quot;panic!&quot;</span>)
 
1028
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">callShutdown</span>(<span class="py-src-parameter">self</span>):
 
1029
        <span class="py-src-keyword">print</span> <span class="py-src-string">&quot;telling them to shut down&quot;</span>
 
1030
        <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">&quot;shutdown&quot;</span>)
 
1031
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">callFour</span>(<span class="py-src-parameter">self</span>):
 
1032
        <span class="py-src-variable">self</span>.<span class="py-src-variable">doCall</span>(<span class="py-src-string">&quot;callFour: call on stale reference&quot;</span>, <span class="py-src-string">&quot;dummy&quot;</span>)
 
1033
 
 
1034
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">got_obj</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">obj</span>):
 
1035
        <span class="py-src-variable">self</span>.<span class="py-src-variable">remote</span> = <span class="py-src-variable">obj</span>
 
1036
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">1</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">callOne</span>)
 
1037
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">2</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">callTwo</span>)
 
1038
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">3</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">callThree</span>)
 
1039
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">4</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">callShutdown</span>)
 
1040
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">5</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">callFour</span>)
 
1041
        <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">6</span>, <span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>)
 
1042
 
 
1043
<span class="py-src-variable">factory</span> = <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBClientFactory</span>()
 
1044
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-number">8800</span>, <span class="py-src-variable">factory</span>)
 
1045
<span class="py-src-variable">deferred</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">getRootObject</span>()
 
1046
<span class="py-src-variable">deferred</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">One</span>().<span class="py-src-variable">got_obj</span>)
 
1047
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
 
1048
</pre><div class="caption">Source listing - <a href="listings/pb/trap_client.py"><span class="filename">listings/pb/trap_client.py</span></a></div></div>
 
1049
 
 
1050
<pre class="shell" xml:space="preserve">
 
1051
% ./trap_client.py 
 
1052
callOne: call with safe object
 
1053
 method successful, response: response
 
1054
callTwo: call with dangerous object
 
1055
 InsecureJelly: you tried to send something unsafe to them
 
1056
callThree: call that raises remote exception
 
1057
 remote raised a MyException
 
1058
telling them to shut down
 
1059
callFour: call on stale reference
 
1060
 stale reference: the client disconnected or crashed
 
1061
 
1062
</pre>
 
1063
 
 
1064
 
 
1065
<p>In this example, <code>callTwo</code> tries to send an instance of a
 
1066
locally-defined class through <code>callRemote</code>. The default security
 
1067
model implemented by <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Jelly.html" title="twisted.spread.pb.Jelly">pb.Jelly</a></code>
 
1068
on the remote end will not allow unknown classes to be unserialized (i.e.
 
1069
taken off the wire as a stream of bytes and turned back into an object: a
 
1070
living, breathing instance of some class): one reason is that it does not
 
1071
know which local class ought to be used to create an instance that
 
1072
corresponds to the remote object<a href="#footnote-5" title="The naive approach of simply doing import SomeClass to match a remote caller who claims to have an object of type SomeClass could have nasty consequences for some modules that do significant operations in their __init__ methods (think telnetlib.Telnet(host='localhost', port='chargen'), or even more powerful classes that you have available in your server program). Allowing a remote entity to create arbitrary classes in your namespace is nearly equivalent to allowing them to run arbitrary code. The pb.InsecureJelly exception arises because the class being sent over the wire has not been registered with the serialization layer (known as jelly). The easiest way to make it possible to copy entire class instances over the wire is to have them inherit from pb.Copyable, and then to use setUnjellyableForClass(remoteClass, localClass) on the receiving side. See Passing Complex Types for an example."><super>5</super></a>.
 
1073
 
 
1074
The receiving end of the connection gets to decide what to accept and what
 
1075
to reject. It indicates its disapproval by raising a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.InsecureJelly.html" title="twisted.spread.pb.InsecureJelly">pb.InsecureJelly</a></code> exception. Because it occurs
 
1076
at the remote end, the exception is returned to the caller asynchronously,
 
1077
so an <code>errback</code> handler for the associated <code>Deferred</code>
 
1078
is run. That errback receives a <code>Failure</code> which wraps the
 
1079
<code>InsecureJelly</code>.</p>
 
1080
 
 
1081
 
 
1082
<p>Remember that <code>trap</code> re-raises exceptions that it wasn't asked
 
1083
to look for. You can only check for one set of exceptions per errback
 
1084
handler: all others must be checked in a subsequent handler.
 
1085
<code>check_MyException</code> shows how multiple kinds of exceptions can be
 
1086
checked in a single errback: give a list of exception types to
 
1087
<code>trap</code>, and it will return the matching member. In this case, the
 
1088
kinds of exceptions we are checking for (<code>MyException</code> and
 
1089
<code>MyOtherException</code>) may be raised by the remote end: they inherit
 
1090
from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Error.html" title="twisted.spread.pb.Error">pb.Error</a></code>.</p>
 
1091
 
 
1092
<p>The handler can return <code>None</code> to terminate processing of the
 
1093
errback chain (to be precise, it switches to the callback that follows the
 
1094
errback; if there is no callback then processing terminates). It is a good
 
1095
idea to put an errback that will catch everything (no <code>trap</code>
 
1096
tests, no possible chance of raising more exceptions, always returns
 
1097
<code>None</code>) at the end of the chain. Just as with regular <code>try:
 
1098
except:</code> handlers, you need to think carefully about ways in which
 
1099
your errback handlers could themselves raise exceptions. The extra
 
1100
importance in an asynchronous environment is that an exception that falls
 
1101
off the end of the <code>Deferred</code> will not be signalled until that
 
1102
<code>Deferred</code> goes out of scope, and at that point may only cause a
 
1103
log message (which could even be thrown away if <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.log.startLogging.html" title="twisted.python.log.startLogging">log.startLogging</a></code> is not used to point it at
 
1104
stdout or a log file). In contrast, a synchronous exception that is not
 
1105
handled by any other <code>except:</code> block will very visibly terminate
 
1106
the program immediately with a noisy stack trace.</p>
 
1107
 
 
1108
<p><code>callFour</code> shows another kind of exception that can occur
 
1109
while using <code>callRemote</code>: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.DeadReferenceError.html" title="twisted.spread.pb.DeadReferenceError">pb.DeadReferenceError</a></code>. This one occurs when the
 
1110
remote end has disconnected or crashed, leaving the local side with a stale
 
1111
reference. This kind of exception happens to be reported right away (XXX: is
 
1112
this guaranteed? probably not), so must be caught in a traditional
 
1113
synchronous <code>try: except pb.DeadReferenceError</code> block. </p>
 
1114
 
 
1115
<p>Yet another kind that can occur is a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.PBConnectionLost.html" title="twisted.spread.pb.PBConnectionLost">pb.PBConnectionLost</a></code> exception. This occurs
 
1116
(asynchronously) if the connection was lost while you were waiting for a
 
1117
<code>callRemote</code> call to complete. When the line goes dead, all
 
1118
pending requests are terminated with this exception. Note that you have no
 
1119
way of knowing whether the request made it to the other end or not, nor how
 
1120
far along in processing it they had managed before the connection was
 
1121
lost. XXX: explain transaction semantics, find a decent reference.</p>
 
1122
 
 
1123
<h2>Footnotes</h2><ol><li><a name="footnote-1"><span class="footnote">There are a few other classes
 
1124
that can bestow this ability, but pb.Referenceable is the easiest to
 
1125
understand; see 'flavors' below for details on the others.</span></a></li><li><a name="footnote-2"><span class="footnote">This can be overridden, by subclassing one of
 
1126
the Serializable flavors and defining custom serialization code for your
 
1127
class. See <a href="pb-copyable.html" shape="rect">Passing Complex Types</a> for
 
1128
details.</span></a></li><li><a name="footnote-3"><span class="footnote">The binary nature of this
 
1129
local vs. remote scheme works because you cannot give RemoteReferences to a
 
1130
third party. If you could, then your object A could go to B, B could give it to
 
1131
C, C might give it back to you, and you would be hard pressed to tell if the
 
1132
object lived in C's memory space, in B's, or if it was really your own object,
 
1133
tarnished and sullied after being handed down like a really ugly picture that
 
1134
your great aunt owned and which nobody wants but which nobody can bear to throw
 
1135
out. Ok, not really like that, but you get the idea.</span></a></li><li><a name="footnote-4"><span class="footnote">To be precise,
 
1136
the Failure will be sent if <em>any</em> exception is raised, not just
 
1137
pb.Error-derived ones. But the server will print ugly error messages if you
 
1138
raise ones that aren't derived from pb.Error.</span></a></li><li><a name="footnote-5"><span class="footnote"><p>The naive approach of simply doing <code>import
 
1139
SomeClass</code> to match a remote caller who claims to have an object of
 
1140
type <q>SomeClass</q> could have nasty consequences for some modules that do
 
1141
significant operations in their <code>__init__</code> methods (think
 
1142
<code>telnetlib.Telnet(host='localhost', port='chargen')</code>, or even
 
1143
more powerful classes that you have available in your server program).
 
1144
Allowing a remote entity to create arbitrary classes in your namespace is
 
1145
nearly equivalent to allowing them to run arbitrary code.</p>
 
1146
 
 
1147
<p>The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.InsecureJelly.html" title="twisted.spread.pb.InsecureJelly">pb.InsecureJelly</a></code>
 
1148
exception arises because the class being sent over the wire has not been
 
1149
registered with the serialization layer (known as <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.jelly.html" title="twisted.spread.jelly">jelly</a></code>). The easiest way to make it possible to
 
1150
copy entire class instances over the wire is to have them inherit from <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.spread.pb.Copyable.html" title="twisted.spread.pb.Copyable">pb.Copyable</a></code>, and then to use
 
1151
<code>setUnjellyableForClass(remoteClass, localClass)</code> on the
 
1152
receiving side. See <a href="pb-copyable.html" shape="rect">Passing Complex Types</a>
 
1153
for an example.</p></span></a></li></ol></div>
 
1154
 
 
1155
    <p><a href="index.html">Index</a></p>
 
1156
    <span class="version">Version: 10.0.0</span>
 
1157
  </body>
 
1158
</html>
 
 
b'\\ No newline at end of file'