Search code examples
pythonconsoleipythontornadospyder

ipython doesn't execute codes like python


I am trying to do this API call: (which is named wwo.py)

# -*- coding: utf-8 -*-
from tornado.httpclient import AsyncHTTPClient

http_client = AsyncHTTPClient()
url = ''
response = ''


def meteo(q='', key=''):
    if len(key) != 29:
        print 'Please provide a valid key'
    elif q == '':
        print 'please provide a valid city name or zip'
    global url
    url = 'http://api.worldweatheronline.com/free/v2/weather.ashx?q={0}&format=json&key= {1}'.format(q, key)

    def handle_request(resp):
        global response
        if resp.error:
            print "Error:", resp.error
        else:
            response = resp.body

    http_client.fetch(url, handle_request)

If I try to call this file and execute it from normal python console, I don't get a response which stays ''.
But if I call it using IPython console, or execute it using Spyder, it calls the response and even if I don't initialize it, it is called!

import wwo

wwo.meteo(q='London', key='API_FREE_KEY')

wwo.response # returns '' on normal python console, returns the full response on ipython console

Solution

  • AsyncHTTPClient.fetch is an asynchronous method. It returns immediately, and the processing of the request and response happen in the IOLoop. When you run your code in plain Python, or the plain IPython terminal, no IOLoop is running, so the request never actually happens.

    The result is different when you run it in IPython via the qtconsole (Spyder) or the Notebook, because IPython itself is already running a tornado IOLoop, so the asynchronous events eventually fire, and your callback is called.

    Based on the provided code, it looks like you want to use the blocking HTTPClient, rather than AsyncHTTPClient, which would look something like this:

    from tornado.httpclient import HTTPClient
    http_client = HTTPClient()
    ...
    resp = http_client.fetch(url) # returns HTTPResponse when it is complete
    response_body = resp.body
    

    Depending on the context of your application, however, you may actually want to use the AsyncHTTPClient, in which case you will need to integrate the IOLoop with your application. If that is already a tornado application, then the best way is probably to use tornado's async functionality via the Future that AsyncHTTPClient.fetch returns. Otherwise, you may end up doing IOLoop.run_sync(), which offers no significant benefit over using the blocking HTTPClient, unless you are writing a function that you want to be able to use in both an async tornado context and a synchronous context.