Hi all I am a new user to the Twisted framework so this might be a trivial question, but here goes.. Im trying to use the Web module and adbapi module to create a (rest) webservice but I am having problems using the adbapi. As fare as I could figure out, the runInteraction call spawns a new thread and executes the sql in that, and the render_GET handler is then returning right away -bummer. I need the adbapi for its db pool but dont need it to be "blocking" so that I can return the result of the db interaction as xml. Hope you guys can help me out or give me some pointers if I am doing this the wrong way. Regards Søren ----- Code ---- from twisted.web import server from twisted.internet import reactor from twisted.enterprise import adbapi from xml.dom.minidom import Document class Simple(Resource): isLeaf=True def __init__(self,opt): Resource.__init__(self) self.opt=opt def render_GET(self,request): doc=Document() self.opt.dbpool.runInteraction(self._getUserList,doc) print "returning result" return doc.toprettyxml(indent=" ") def _getUserList(self,txn,doc): txn.execute("SELECT UserName FROM User ") res = txn.fetchall() if (res): for row in res: print row usr=doc.createElement("user") usr.setAttribute("name","%s" % (row[0] )) class options: pass if __name__ == '__main__': options.dbpool= adbapi.ConnectionPool("MySQLdb", host='localhost',db='TrackingPresentation', user='web', passwd='tingogsager') site = server.Site(Simple(options)) reactor.listenTCP(8888,site) reactor.run() ------ Code ------
On 7/21/07, Søren Bach Christiansen <sbc@my-place.biz> wrote:
Hi all
I am a new user to the Twisted framework so this might be a trivial question, but here goes..
Im trying to use the Web module and adbapi module to create a (rest) webservice but I am having problems using the adbapi. As fare as I could figure out, the runInteraction call spawns a new thread and executes the sql in that, and the render_GET handler is then returning right away -bummer. I need the adbapi for its db pool but dont need it to be "blocking" so that I can return the result of the db interaction as xml.
Hope you guys can help me out or give me some pointers if I am doing this the wrong way.
Regards Søren
----- Code ---- from twisted.web import server from twisted.internet import reactor from twisted.enterprise import adbapi from xml.dom.minidom import Document
class Simple(Resource): isLeaf=True def __init__(self,opt): Resource.__init__(self) self.opt=opt
def render_GET(self,request): doc=Document() self.opt.dbpool.runInteraction(self._getUserList,doc) print "returning result" return doc.toprettyxml(indent=" ")
def _getUserList(self,txn,doc): txn.execute("SELECT UserName FROM User ") res = txn.fetchall() if (res): for row in res: print row usr=doc.createElement("user") usr.setAttribute("name","%s" % (row[0] ))
class options: pass
if __name__ == '__main__': options.dbpool= adbapi.ConnectionPool("MySQLdb", host='localhost',db='TrackingPresentation', user='web', passwd='tingogsager') site = server.Site(Simple(options)) reactor.listenTCP(8888,site) reactor.run()
------ Code ------
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
You did all the hard work already. The only thing you need to do is connect the database query to the render_GET rendering method's output. You want to take the Deferred that ruInteraction returns (yes it runs in a separate thread async), add a callback to it that converts the xml to a string (called cb below), then return that Deferrred in render_GET. Here's untested code: def render_GET(self,request): doc=Document() def cb(PARAM_NOT_USED): print "returning result" return doc.toprettyxml(indent=" ") return self.opt.dbpool.runInteraction (self._getUserList,doc).addCallback(cb) If I was writing this code, I would probably have _getUserList create and return the doc, in which case the code would look like this: def render_GET(self,request): def cb(doc): # now doc is passed to the callback from _getUserList print "returning result" return doc.toprettyxml(indent=" ") return self.opt.dbpool.runInteraction (self._getUserList).addCallback(cb) Cheers, Christian
Thanks for the response Christian. Unfortunately im still not quite there yet. took you advice and change the code to read: ----- Snip ---- def render_GET(self,request): def cb(text): print text ### This text looks like it should return text return self.opt.dbpool.runInteraction(self._getUserList).addCallback (cb) def _getUserList(self,txn): doc=Document() camp= doc.createElement("userlist") doc.appendChild(camp) txn.execute("SELECT UserName FROM User ") res = txn.fetchall() if (res): for row in res: usr=doc.createElement("user") camp.appendChild(usr) usr.setAttribute("name","%s" % (row[0] )) return doc.toprettyxml(indent=" ") ----- Snip ---- But still think the problem is basically the same as before. The runInteraction returns a Defered object that I now add a callback function to. But the addCallback(cb) returns right away and the return value is still the Defered object. So the webserver gives an error saying something like: Request did not return a string Request: <GET / HTTP/1.1> Resource: <__main__.Simple instance at 0x1208878> Value: <Deferred at 0x124cfa8> Later when the _getUserList() returns the Defered object calles the cb () function and i get a printout with the wanted result. So I think my problem is that I whant to *wait* for the result from the db query before the render_GET() returns. /Søren On Jul 21, 2007, at 15:34 , Christian Simms wrote:
On 7/21/07, Søren Bach Christiansen <sbc@my-place.biz> wrote: Hi all
I am a new user to the Twisted framework so this might be a trivial question, but here goes..
Im trying to use the Web module and adbapi module to create a (rest) webservice but I am having problems using the adbapi. As fare as I could figure out, the runInteraction call spawns a new thread and executes the sql in that, and the render_GET handler is then returning right away -bummer. I need the adbapi for its db pool but dont need it to be "blocking" so that I can return the result of the db interaction as xml.
Hope you guys can help me out or give me some pointers if I am doing this the wrong way.
Regards Søren
----- Code ---- from twisted.web import server from twisted.internet import reactor from twisted.enterprise import adbapi from xml.dom.minidom import Document
class Simple(Resource): isLeaf=True def __init__(self,opt): Resource.__init__(self) self.opt=opt
def render_GET(self,request): doc=Document() self.opt.dbpool.runInteraction(self._getUserList,doc) print "returning result" return doc.toprettyxml(indent=" ")
def _getUserList(self,txn,doc): txn.execute("SELECT UserName FROM User ") res = txn.fetchall() if (res): for row in res: print row usr=doc.createElement("user") usr.setAttribute("name","%s" % (row[0] ))
class options: pass
if __name__ == '__main__': options.dbpool= adbapi.ConnectionPool("MySQLdb", host='localhost',db='TrackingPresentation', user='web', passwd='tingogsager') site = server.Site(Simple(options)) reactor.listenTCP(8888,site) reactor.run()
------ Code ------
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
You did all the hard work already. The only thing you need to do is connect the database query to the render_GET rendering method's output. You want to take the Deferred that ruInteraction returns (yes it runs in a separate thread async), add a callback to it that converts the xml to a string (called cb below), then return that Deferrred in render_GET. Here's untested code:
def render_GET(self,request): doc=Document() def cb(PARAM_NOT_USED): print "returning result" return doc.toprettyxml(indent=" ") return self.opt.dbpool.runInteraction (self._getUserList,doc).addCallback(cb)
If I was writing this code, I would probably have _getUserList create and return the doc, in which case the code would look like this:
def render_GET(self,request): def cb(doc): # now doc is passed to the callback from _getUserList print "returning result" return doc.toprettyxml(indent=" ") return self.opt.dbpool.runInteraction (self._getUserList).addCallback(cb)
Cheers, Christian
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
Request did not return a string Request: <GET / HTTP/1.1>
Resource: <__main__.Simple instance at 0x1208878>
Value: <Deferred at 0x124cfa8>
Later when the _getUserList() returns the Defered object calles the cb() function and i get a printout with the wanted result.
So I think my problem is that I whant to *wait* for the result from the db query before the render_GET() returns.
No, you definitely don't wait - that defeats the entire point of using an event-driven system. See: http://twistedmatrix.com/documents/current/api/twisted.web.resource.IResourc... Basically: def render_GET(self, request): def cb(data): request.write(data) # note, we add our callback to the deferred then discard it self.opt.dbpool.runInteraction(blah).addCallback(cb) # we *return* a special value return server.NOT_DONE_YET HTH
Oops, sorry that should be: def render_GET(self, request): def cb(data): request.write(data) request.finish() # note, we add our callback to the deferred then discard it self.opt.dbpool.runInteraction(blah).addCallback(cb) # we *return* a special value return server.NOT_DONE_YET
Now it makes sense, specially liked the NOT.DONE.YET variable :) Hole thing worked like a charm, thanks a million /Søren On Jul 21, 2007, at 16:58 , Phil Mayers wrote:
Oops, sorry that should be:
def render_GET(self, request): def cb(data): request.write(data) request.finish()
# note, we add our callback to the deferred then discard it self.opt.dbpool.runInteraction(blah).addCallback(cb)
# we *return* a special value return server.NOT_DONE_YET
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
participants (3)
-
Christian Simms
-
Phil Mayers
-
Søren Bach Christiansen