[Twisted-Python] adbapi weirdness
Andrew Bennetts
andrew-twisted at puzzling.org
Wed Jul 30 23:08:49 MDT 2003
On Wed, Jul 30, 2003 at 09:30:27PM -0700, Steve Freitas wrote:
> > > Hi all,
> > >
> > > Here's the latest thing I can't figure out.
> > >
> > > If I do this and make an XML-RPC call to dbtest(), it runs fine:
> > >
> > > class takeOne(xmlrpc.XMLRPC):
> > > def __init__(self):
> > > self.dbpool = adbapi.ConnectionPool("pyPgSQL.PgSQL", \
> > > host='127.0.0.1', user='postgres', database='template1')
> > > self.db = adbapi.Augmentation(self.dbpool)
> > > self.prefs = Env(self.db)
[...]
> > >
> > > def xmlrpc_listPrefs(self):
> > > return self.prefs.prefs
> > >
> > > class Env:
> > > def __init__(self, db):
> > > self.db = db
> > > self.prefs = self.db.runQuery("select * from prefs")
[...]
> > > But a call to listPrefs() hangs until I make another, concurrent
> > > request to dbtest(), at which point it comes through. Then if I try
> > > listPrefs() again, it returns Fault 8002: Can't serialize output.
> >
> > You can't send the same Deferred more than once.
>
> Err, can you give it to me in NewbieSpeaque(tm)? :-)
I'll try :)
runQuery returns a Deferred. If you don't know what that is, you're going
to run into bigger problems than just this, so speak up now :) -- and read:
twistedmatrix.com/documents/howto/defer
Now, for twisted.web.xmlrpc to get the results of your deferred, it has to
add a callback to it. This callback consumes the result of your deferred
(although I don't see any reason why this *has* to be the case, necessarily,
but I can see how it could avoid confusing errors, so it's probably a good
idea). This means that the next callback added to that deferred will get a
result of None, which can't be represented in XML-RPC, hence the error.
One way to work around this would be something like this (completely
untested, of course...):
----
from twisted.web import xmlrpc
from twisted.internet import defer
from twisted.python import log
from twisted.enterprise import adbapi
class TakeOne(xmlrpc.XMLRPC):
def __init__(self):
self.dbpool = adbapi.ConnectionPool("pyPgSQL.PgSQL", \
host='127.0.0.1', user='postgres', database='template1')
self.db = adbapi.Augmentation(self.dbpool)
self.prefs = Env(self.db)
def xmlrpc_listPrefs(self):
return self.prefs.getPrefs()
class Env:
def __init__(self, db):
self.db = db
self.prefs = None
self.outstandingRequests = []
self.d = self.db.runQuery("select * from prefs")
d.addCallbacks(self._cb, self._eb)
def getPrefs(self):
if self.prefs is not None:
return self.prefs
else:
d = defer.Deferred()
self.outstandingRequests.append(d)
return d
def _cb(self, result):
self.prefs = results
for d in self.outstandingRequests:
d.callback(result)
del self.outstandingRequests[:]
def _eb(self, failure):
self.prefs = results
log.err(failure)
----
-Andrew.
More information about the Twisted-Python
mailing list