Search code examples
pythontornado

Call not recognised and use instead Future


When running my tornado script which should send a request and get the body of the response and append this to some html code on a localhost port. However, I get this error:

TypeError: init() got an unexpected keyword argument 'callback'

It turns out from the documentation Asynchronous HTTP client that the callback has been removed for Future

Changed in version 6.0: The callback argument was removed. Use the returned Future instead.

There are a lack of effective examples and so what is the most appropriate method to use Future in replacement for callback in my script?

import asyncio
import os
import json
import tornado.httpclient
import tornado.web
import tornado.httpserver
import tornado.gen
from tornado.options import define, options
define('port', default = 9060, help="run port 9060", type=int)

class requestFour(tornado.web.RequestHandler):
    @tornado.gen.coroutine
    def get(self):
        #arg = self.get_argument('stock')
        client = tornado.httpclient.AsyncHTTPClient()
        yield client.fetch('https://books.toscrape.com', callback=self.on_response)

    def on_response(self, response):
        body = json.load(response.body)
        self.write("""
                    <div style="text-align: center">
                    <div style="font-size: 72px">%s</div>
                    <div style="font-size: 144px">%.02f</div>
                    <div style="font-size: 24px">tweets per second</div>
                    </div>
                    """ % (body)) 
        self.finish()

def my_app():
    app = tornado.web.Application(handlers = [(r'/', requestFour)])
    http_server = tornado.httpserver.HTTPServer(app)
    return http_server

async def main():
    app = my_app()
    app.listen(options.port)
    shutdown_event = asyncio.Event()
    await shutdown_event.wait()

if __name__ == '__main__':
    asyncio.run(main())

Solution

  • You can just call self.on_response directly:

    response = yield client.fetch('https://books.toscrape.com')
    self.on_response(response)
    

    Additional notes:

    Make your life easier by ditching @gen.coroutine and yield and switching to async/await:

    async def get(self):
        #arg = self.get_argument('stock')
        client = tornado.httpclient.AsyncHTTPClient()
        response = await client.fetch('https://books.toscrape.com')
        self.on_response(response)