Abdelouahab Abdelouahab - 4 months ago 15
Python Question

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

Answer

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.