Python BadYieldError when yielding Future
Question: I'm fairly new to programming using coroutines and I'm trying to build a
database interface for a custom database for a Tornado web server using Python
2.7.10. However, I keep getting a `BadYieldError`. I feel that this is
probably me not understanding how to fully use `tornado.gen.coroutine` with
Python's `yield`. I think there may be something wrong with how I'm yielding a
Future.

This is my code that keeps failing, where the `testGet` function at line 15 is
a simulation of a foreign database access.

    
    
    from tornado import gen
    import tornado.ioloop
    import tornado.web
    
    
    class MainHandler(tornado.web.RequestHandler):
        @gen.coroutine
        def get(self):
            response = "Hello, world"
            response = yield db_interface("default", "user_query")
            self.write(str(response))
    
    
    # meant to demonstrate
    def testGet(query):
        gen.sleep(2)
        response = query
        return response
    
    
    @gen.coroutine
    def db_interface(db, key):
        print str(db)
        d = yield testGet(key)
        raise gen.Return(d)
    
    
    def make_app():
        return tornado.web.Application([
            (r"/", MainHandler),
        ])
    
    
    if __name__ == "__main__":
        app = make_app()
        app.listen(8889)
        tornado.ioloop.IOLoop.current().start()
    

Output:

    
    
    default
    ERROR:tornado.application:Uncaught exception GET / (127.0.0.1)
    HTTPServerRequest(protocol='http', host='127.0.0.1:8889', method='GET', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Accept-Language': 'en-CA,en;q=0.8,fr;q=0.6', 'Accept-Encoding': 'gzip, deflate, sdch', 'Host': '127.0.0.1:8889', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36', 'Dnt': '1', 'Connection': 'keep-alive', 'Cookie': 'ui-auth-127.0.0.1%3A8091=4f1301ef98f1b6fbd80ad059cd5aa2dc', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1'})
    Traceback (most recent call last):
      File "/usr/local/lib/python2.7/site-packages/tornado/web.py", line 1415, in _execute
        result = yield result
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
        value = future.result()
      File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
        raise_exc_info(self._exc_info)
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
        yielded = self.gen.throw(*exc_info)
      File "test.py", line 12, in get
        response = yield db_interface("default", "user_query")
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
        value = future.result()
      File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
        raise_exc_info(self._exc_info)
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 876, in run
        yielded = self.gen.throw(*exc_info)
      File "test.py", line 26, in db_interface
        d = yield testGet(key)
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 870, in run
        value = future.result()
      File "/usr/local/lib/python2.7/site-packages/tornado/concurrent.py", line 215, in result
        raise_exc_info(self._exc_info)
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 956, in handle_yield
        self.future = convert_yielded(yielded)
      File "/usr/local/lib/python2.7/site-packages/tornado/gen.py", line 1026, in convert_yielded
        raise BadYieldError("yielded unknown object %r" % (yielded,))
    BadYieldError: yielded unknown object 'user_query'
    ERROR:tornado.access:500 GET / (127.0.0.1) 2011.67ms
    

I've been trying to look for how to do this properly on [Tornado's official
documentation](http://www.tornadoweb.org/en/stable/guide/coroutines.html) and
on [this blog](https://emptysqua.re/blog/refactoring-tornado-coroutines/), but
I don't think I've been able to fully grasp what they're saying about how to
use coroutines.


Answer: Either turn `testGet` into a coroutine like this so that it returns a future:

    
    
    @gen.coroutine
    def testGet(query):
        gen.sleep(2)
        raise gen.Return(query)
    

Or don't use `yield` on it: `d = testGet(key)`.

If you do either, the code works. You should be using `yield` on functions
that return `Future`s.

