3

I'm trying to use Corduroy to talk to a CouchDB asynchronously using the python Tornado Web Server.

The code below comes from the Corduroy guide, with a couple of alterations.

import tornado.web
from corduroy import Database, NotFound, relax

people_db = Database('people')

class RelaxedHello(tornado.web.RequestHandler):
    @relax
    def get(self, user_id):
        try:
            doc = yield people_db.get(user_id)
            self.write('hello %s'%(doc['name']))
        except NotFound:
            self.write('hello whoever you are')
        self.finish()

application = tornado.web.Application([
    (r'/hi/([^/]+)', RelaxedHello),
]).listen(1920)
tornado.ioloop.IOLoop.instance().start()

The problem I'm having is that I receive a BadYieldError despite finding the couch document perfectly well. I suspect it's something to do with the tornado.gen module not being set up properly (or something?). Using corduroy without the @relax decorator, and with a callback works fine.

Traceback (most recent call last):
  File "c:\env\pymeals_tornado\lib\site-packages\tornado\web.py", line 1074, in wrapper
    return method(self, *args, **kwargs)
  File "c:\env\pymeals_tornado\lib\site-packages\corduroy\__init__.py", line 43,  in _r_e_l_a_x_
    return gen.engine(_func_)(*args, **kwargs)
  File "c:\env\pymeals_tornado\lib\site-packages\tornado\gen.py", line 107, in wrapper
    runner.run()
  File "c:\env\pymeals_tornado\lib\site-packages\tornado\gen.py", line 319, in run
    yielded = self.gen.throw(*exc_info)
  File "test.py", line 10, in get
    doc = yield people_db.get(user_id)
BadYieldError: yielded unknown object <Document 65d936ee54417e46479a908f7a0038ef[2] {name:Colin}>
colinjwebb
  • 4,362
  • 7
  • 31
  • 35
  • Have you tried to use `gen` module directly? – Nikolay Fominyh Jul 16 '12 at 12:58
  • Not yet. I'm still learning Tornado, and haven't used it before. I might have a play with it later, thanks! – colinjwebb Jul 16 '12 at 16:07
  • Using the gen module directly yields good results, however I'd still like to try with corduroy. Investigating again this evening... – colinjwebb Jul 17 '12 at 18:52
  • I'm not sure about quality of @relax decorator. Try to dig into it's code and understand what features of tornado it is using. – Nikolay Fominyh Jul 17 '12 at 20:28
  • The @relax decorator looks like it just replaces using both asynchronous and tornado.gen.engine decorators. However, I still have to use "doc = yield tornado.gen.Task(people_db.get, user_id)" to do anything :( – colinjwebb Jul 18 '12 at 20:26

1 Answers1

0

Reading the code for relax and for get(), it looks to me like corduroy's 3-year-old code is not designed for the most modern Tornado idioms. Specifically, get takes a callback, rather than returning a Future as modern Tornado APIs do.

That means you'll have to use an older style with gen.Task like:

from tornado import gen

class RelaxedHello(tornado.web.RequestHandler):
    @relax
    def get(self, user_id):
        try:
            doc = yield gen.Task(people_db.get, user_id)
            self.write('hello %s'%(doc['name']))
        except NotFound:
            self.write('hello whoever you are')
        self.finish()

I haven't tested this, let me know how it goes. More info on gen.Task is in the Tornado documentation.

A. Jesse Jiryu Davis
  • 23,641
  • 4
  • 57
  • 70
  • Thanks for the answer. I seem to remember doing something similar, but I have now stopped using Tornado, so I'll have to leave it to someone else to verify this is correct. – colinjwebb Aug 10 '15 at 08:52