Sharing Python Objects with Perspective Broker

XML-RPC and SOAP both transfer data using XML, which makes them language- and platform-neutral. This is an advantage most of the time. But what if you want to communicate between two Twisted applications without having to interoperate with anything else? In that case, the cross-platform advantages of XML could introduce a lot of work, as you have to convert your objects into formats that can be serialized as XML elements. A better approach might be to use Twisted Spread , a system for RPC that uses serialized Python objects.

5.8.1. How Do I Do That?

The core of Twisted Spread is Perspective Broker, which manages connections and handles calls to and from remote objects. The Perspective Broker module is named pb, which has resulted in a large number of peanut-butter-sandwich-related puns and module names (two of the other modules in Spread are banana and jelly).

Perspective Broker is conservative about what it exposes to the network. To avoid security holes, you have to specify exactly which objects should be able to be accessed remotely, and which methods you want to make available over the network. The pb module contains several different classes that you can inherit from to provide remotely accessible objects and methods. It also provides a PBServerFactory class for managing a Perspective Broker server. Example 5-7 shows how to run a server that shares Wiki data using Perspective Broker.

Example 5-7.

from twisted.spread import pb

import wiki

class WikiPerspective(pb.Root):

 def _ _init_ _(self, wikiData):

 self.wikiData = wikiData

 def remote_hasPage(self, path):

 return self.wikiData.hasPage(path)

 def remote_listPages(self):

 return self.wikiData.listPages( )

 def remote_getPage(self, path):

 return self.wikiData.getPage(path)

 def remote_getRenderedPage(self, path):

 return self.wikiData.getRenderedPage(path)

 def remote_setPage(self, path, data):

 self.wikiData.setPage(path, data)

 def remote_getReporter(self):

 return RemoteWikiReporter(self.wikiData)

class WikiReporter(pb.Referenceable):

 "I do simple reporting tasks in the wiki"

 def _ _init_ _(self, wikiData):

 self.wikiData = wikiData

 def listNeededPages(self):

 "return a list of pages that are linked to but don't exist yet"

 allPages = [self.wikiData.getPage(p)

 for p in self.wikiData.listPages( )]

 neededPages = []

 for page in allPages:

 wikiWords = [match[0]

 for match in wiki.reWikiWord.findall(page)]

 for pageName in wikiWords:

 if not self.wikiData.hasPage(pageName):


 return neededPages

if __name__ == "_ _main_ _":

 import sys

 from twisted.internet import reactor

 datafile = sys.argv[1]

 wikiData = wiki.WikiData(datafile)

 wikiPerspective = WikiPerspective(wikiData)

 reactor.listenTCP(8789, pb.PBServerFactory(wikiPerspective)) )

Run with one argument, the name of the Wiki datafile:

 $ python wiki.dat

Now you need a client to connect to the server. Example 5-8 shows a basic Perspective Broker client.

Example 5-8.

from twisted.spread import pb

from twisted.internet import reactor

class PbTester(object):

 def _ _init_ _(self): = None

 def runTests(self):

 self.connect( ).addCallback(

 lambda _: self.listPages( )).addCallback(

 lambda _: self.createTestPage( )).addCallback(

 lambda _: self.getTestPage( )).addCallback(

 lambda _: self.runReports( )).addErrback(


 lambda _: reactor.stop( ))

 def connect(self):

 factory = pb.PBClientFactory( )

 reactor.connectTCP("localhost", 8789, factory)

 return factory.getRootObject( ).addCallback(self._connected)

 def _connected(self, rootObj): = rootObj

 def listPages(self):

 print "Getting page list..."



 def _gotList(self, pages):

 print "Got page list:", pages

 def createTestPage(self):

 print "Creating test page PbTest..."

 pageData = "This is a test of PerspectiveBroker"

 return'setPage', 'PbTest', pageData)

 def getTestPage(self):

 print "Getting test page content..."


 'getRenderedPage', 'PbTest').addCallback(


 def _gotTestPage(self, content):

 print "Got page content:"

 print content

 return self.listPages( )

 def runReports(self):

 print "Running report..."



 def _gotReporter(self, reporter):

 print "Got remote reporter object"

 return reporter.callRemote('listNeededPages').addCallback(


 def _gotNeededPages(self, pages):

 print "These pages are needed:", pages

 def _catchFailure(self, failure):

 print "Error:", failure.getErrorMessage( )

t = PbTester( )

t.runTests( ) )

Run, and it will call functions on the server using the Perspective Broker protocol:

 $ python

 Getting page list...

 Got page list: ['WikiHome', 'CurlTest', 'SoapTest', 'XmlRpcTest', 'WgetTest',

 'RestTest', 'PythonXmlRpcTest']

 Creating test page PbTest...

 Getting test page content...

 Got page content:

 This is a test of <a href="PerspectiveBroker">PerspectiveBroker</a>

 Getting page list...

 Got page list: ['WikiHome', 'CurlTest', 'SoapTest', 'XmlRpcTest', 'WgetTest',

 'RestTest', 'PbTest', 'PythonXmlRpcTest']

 Running report...

 Got remote reporter object

 These pages are needed: ['AnotherWikiPage', 'SoapRpc', 'XmlRpc', 'HttpPut',

 'PerspectiveBroker', 'XmlRpc']


5.8.2. How Does That Work?

The server creates subclasses of classes in the twisted.spread.pb module. WikiPerspective is a subclass of pb.Root, and WikiReporter is a subclass of pb.Referenceable. Inheriting from these special classes tells Perspective Broker that these objects should be made available for remote access. Methods that should be available remotely must be named with a remote_ prefix.

WikiPerspective inherits from pb.Root, and is passed to the PBServerFactory when it gets created. This makes a WikiPerspective instance available to any client that establishes a connection.

The WikiReporter class in Example 5-7 is an example of how you could expose a second object through Perspective Broker. To make this object available over the network, it inherits from pb.Referenceable. WikiReporter has one method, remote_listNeededPages, which crawls through the Wiki data and returns a list of pages that are mentioned in other pages but have yet to be created.

On the client side, opens a connection to the server. The first thing it has to do is call getrootObject on a PBClientFactory. This returns a Deferred that will call back with a reference to the root object on the remote server once the connection has been established. Once you have the root object, you can call remote methods with the same callRemote syntax used in the XML-RPC and SOAP clients earlier in this chapter.

The server method remote_getReporter is interesting because instead of returning a simple Python type it returns a WikiReporter object. Since WikiReporter inherits from pb.Referenceable, the server knows to give the client a reference to the server-side object. Once it receives this reference, the client can use its callRemote method to call methods on the WikiReporter object that was created on the server.

Example 5-7 doesn't require authentication, and makes no distinction between different users who might be connecting to the server. To learn how to manage authentication and user permissions in Perspective Broker, see Example 6-5.

Getting Started

Building Simple Clients and Servers

Web Clients

Web Servers

Web Services and RPC


Mail Clients

Mail Servers

NNTP Clients and Servers


Services, Processes, and Logging

Twisted Network Programming Essentials
Twisted Network Programming Essentials
ISBN: 0596100329
EAN: 2147483647
Year: 2004
Pages: 107
Authors: Abe Fettig © 2008-2020.
If you may any questions please contact us: