1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: Using Perspective Broker</title>
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
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>
13
<h2>Basic Example<a name="auto0"/></h2>
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>
19
<div class="py-listing"><pre><p class="py-linenumber"> 1
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>
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>
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
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>
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">"localhost"</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">"echo"</span>, <span class="py-src-string">"hello network"</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>
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
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>
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>
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>
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>
112
<p>The callback does:</p>
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">"echo"</span>, <span class="py-src-string">"hello network"</span>)
118
<p>which causes the server's <code>.remote_echo()</code> method to be invoked.
119
(running <code>.callRemote("boom")</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>
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>
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">"hello network"</span>)
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>
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>
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>
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>,
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>
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>
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>
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>
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>
190
<h2>Complete Example<a name="auto1"/></h2>
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>
198
<div class="py-listing"><pre><p class="py-linenumber"> 1
218
</p><span class="py-src-comment">#!/usr/bin/env python</span>
220
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
221
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"Two.three was given"</span>, <span class="py-src-variable">arg</span>
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">"returning a Two called"</span>, <span class="py-src-variable">two</span>
233
<span class="py-src-keyword">return</span> <span class="py-src-variable">two</span>
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
270
</p><span class="py-src-comment">#!/usr/bin/env python</span>
272
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
273
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"localhost"</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>()
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">"error getting first object"</span>, <span class="py-src-variable">reason</span>
287
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
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">"got first object:"</span>, <span class="py-src-variable">obj1</span>
291
<span class="py-src-keyword">print</span> <span class="py-src-string">"asking it to getTwo"</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">"getTwo"</span>)
293
<span class="py-src-variable">def2</span>.<span class="py-src-variable">addCallbacks</span>(<span class="py-src-variable">got_obj2</span>)
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">"got second object:"</span>, <span class="py-src-variable">obj2</span>
297
<span class="py-src-keyword">print</span> <span class="py-src-string">"telling it to do three(12)"</span>
298
<span class="py-src-variable">obj2</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">"three"</span>, <span class="py-src-number">12</span>)
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>
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.
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>
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
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>
336
<h2>References can come back to you<a name="auto2"/></h2>
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>
346
<div class="py-listing"><pre><p class="py-linenumber"> 1
376
</p><span class="py-src-comment">#!/usr/bin/env python</span>
378
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
379
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"two.print was given"</span>, <span class="py-src-variable">arg</span>
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">"One.getTwo(), returning my two called"</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">"One.checkTwo(): comparing my two"</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">"One.checkTwo(): against your two"</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">"One.checkTwo(): our twos are the same"</span>
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
443
</p><span class="py-src-comment">#!/usr/bin/env python</span>
445
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
446
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"localhost"</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>()
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>
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>
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">"got one object:"</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">"asking it to getTwo"</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">"getTwo"</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">step2</span>)
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">"got two object:"</span>, <span class="py-src-variable">two</span>
474
<span class="py-src-keyword">print</span> <span class="py-src-string">"giving it back to one"</span>
475
<span class="py-src-keyword">print</span> <span class="py-src-string">"one is"</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">"checkTwo"</span>, <span class="py-src-variable">two</span>)
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>
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>
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>
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>
508
<h2>References to client-side objects<a name="auto3"/></h2>
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>
517
<div class="py-listing"><pre><p class="py-linenumber"> 1
533
</p><span class="py-src-comment">#!/usr/bin/env python</span>
535
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
536
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"received a Two called"</span>, <span class="py-src-variable">two</span>
544
<span class="py-src-keyword">print</span> <span class="py-src-string">"telling it to print(12)"</span>
545
<span class="py-src-variable">two</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">"print"</span>, <span class="py-src-number">12</span>)
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
576
</p><span class="py-src-comment">#!/usr/bin/env python</span>
578
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
579
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"Two.print() called with"</span>, <span class="py-src-variable">arg</span>
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">"localhost"</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>()
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">"got One:"</span>, <span class="py-src-variable">obj</span>
598
<span class="py-src-keyword">print</span> <span class="py-src-string">"giving it our two"</span>
599
<span class="py-src-variable">obj</span>.<span class="py-src-variable">callRemote</span>(<span class="py-src-string">"takeTwo"</span>, <span class="py-src-variable">two</span>)
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>
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
609
<h2>Raising Remote Exceptions<a name="auto4"/></h2>
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>
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>
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>
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
642
<div class="py-listing"><pre><p class="py-linenumber"> 1
674
</p><span class="py-src-comment">#!/usr/bin/env python</span>
676
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
677
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"""This is an Expected Exception. Something bad happened."""</span>
684
<span class="py-src-keyword">pass</span>
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">"""This is an Unexpected Exception. Something really bad happened."""</span>
688
<span class="py-src-keyword">pass</span>
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">"fall down go boom"</span>
693
<span class="py-src-keyword">print</span> <span class="py-src-string">"raising a MyError exception with data '%s'"</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">"hadda owie"</span>
697
<span class="py-src-keyword">print</span> <span class="py-src-string">"raising a MyError2 exception with data '%s'"</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>)
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>()
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
740
</p><span class="py-src-comment">#!/usr/bin/env python</span>
742
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
743
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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">"localhost"</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>()
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 "broken" into "broken2" 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">"broken"</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>)
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">"erm, it wasn't *supposed* to work.."</span>
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">"got remote Exception"</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">" .__class__ ="</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">" .getErrorMessage() ="</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">" .type ="</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>()
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>
775
<pre class="shell" xml:space="preserve">
778
.__class__ = twisted.spread.pb.CopiedFailure
779
.getErrorMessage() = fall down go boom
780
.type = __main__.MyError
781
Main loop terminated.
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
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>
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>
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>
829
<div class="py-listing"><pre><p class="py-linenumber"> 1
850
</p><span class="py-src-comment">#!/usr/bin/env python</span>
852
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
853
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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>
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">"panic!"</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">"response"</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>()
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
960
</p><span class="py-src-comment">#!/usr/bin/env python</span>
962
<span class="py-src-comment"># Copyright (c) 2009 Twisted Matrix Laboratories.</span>
963
<span class="py-src-comment"># See LICENSE for details.</span>
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>
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>
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>
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">" stale reference: the client disconnected or crashed"</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">" InsecureJelly: you tried to send something unsafe to them"</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">" remote raised a MyException"</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">" something else happened"</span>
989
<span class="py-src-keyword">else</span>:
990
<span class="py-src-keyword">print</span> <span class="py-src-string">" method successful, response:"</span>, <span class="py-src-variable">response</span>
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">" method successful, response:"</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">" InsecureJelly: you tried to send something unsafe to them"</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">" remote raised a MyException"</span>
1003
<span class="py-src-keyword">else</span>:
1004
<span class="py-src-keyword">print</span> <span class="py-src-string">" remote raised a MyOtherException"</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">" something else happened"</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>
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">"fooMethod"</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">" stale reference: the client disconnected or crashed"</span>
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">"callOne: call with safe object"</span>, <span class="py-src-string">"safe string"</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">"callTwo: call with dangerous object"</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">"callThree: call that raises remote exception"</span>, <span class="py-src-string">"panic!"</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">"telling them to shut down"</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">"shutdown"</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">"callFour: call on stale reference"</span>, <span class="py-src-string">"dummy"</span>)
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>)
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">"localhost"</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>
1050
<pre class="shell" xml:space="preserve">
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
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>.
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>
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>
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>
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>
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>
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>
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>
1155
<p><a href="index.html">Index</a></p>
1156
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'