Using any Python module in your Tropo scripting application

In case you didn’t know, Tropo is a set simple and powerful APIs that allow you to build rich voice, IM and text applications in the cloud. It supports many programming languages, Python being among them, of course. Development will also be free, so go and get an account to start playing with it!

With Tropo you can develop applications in 2 ways: hosted scripting or web API. In case you are using the web API, the code runs on your server, so there should be no problem there. When using hosted scripting applications, however, we face limitations imposed by the runtime. The Python interpreter is actually Jython 2.5 and we need to be aware of that. One of the things I really miss is some module to encode / decode JSON.

But hey, didn’t we say we could import modules directly from the web in the previous post? Lets just leverage that and build a test application.

My test application will just reply with a random Chuch Norris quote by using the JSON API provided by The Internet Chuck Norris Database. The good thing about Tropo is that you only need to write your application once, but it’s multi-channel: you may connect to it using Jabber and you’ll get a text back, or you may call it using SIP or Skype, and you’ll listen to the quote using text to speech. Cool uh?!

Lets see the code:

# Derived from: http://paste.pocoo.org/show/407530/
import sys
import imp
import urllib2
import urlparse
class WebImporter(object):
def __init__(self, path):
url = urlparse.urlparse(path)
if url.scheme not in ('http', 'https'):
raise ImportError
self.path = path
self._cache = {}
@classmethod
def register(cls):
sys.path_hooks.append(cls)
def _get_source_and_filename(self, name):
rv = self._cache.get(name)
if rv is not None:
return rv
url_name = name.replace('.', '/')
if url_name.endswith('.py'):
urls = (url_name)
else:
urls = (url_name + '.py', url_name + '/__init__.py')
for filename in urls:
try:
url = urlparse.urljoin(self.path, filename)
try:
resp = urllib2.urlopen(url)
except urllib2.URLError:
continue
if resp.code == 404:
continue
rv = resp.read(), url
self._cache[name] = rv
return rv
except IOError:
continue
raise ImportError(name)
def get_source(self, name):
return self._get_source_and_filename(name)[0]
def get_filename(self, name):
return self._get_source_and_filename(name)[1]
def find_module(self, name, path=None):
try:
self._get_source_and_filename(name)
except ImportError:
return None
return self
def load_module(self, name):
source, filename = self._get_source_and_filename(name)
sys.modules[name] = mod = imp.new_module(name)
mod.__loader__ = self
mod.__file__ = filename
if filename.endswith('/__init__.py'):
mod.__path__ = [filename.rsplit('/', 1)[0]]
exec source in mod.__dict__
return mod
# The 'ifmain trick' can't be used here, when Tropo exeutes this script
# __name__ is set to __builtin__
answer()
WebImporter.register()
sys.path.insert(0, 'http://random.saghul.net/pymodules/')
import simplejson
try:
r = urllib2.urlopen('http://api.icndb.com/jokes/random')
except urllib2.URLError:
say('Error getting Chuck Norris fact')
else:
data = simplejson.loads(r.read())
if data.get('type', None) == 'success':
say(data['value']['joke'])
else:
say('Failure!')
view raw gistfile1.py hosted with ❤ by GitHub

Code should be simple and self-explanatory, leaving out the importing magic. The application is running, you may test it:

Skype Voice: +990009369996104671
SIP Voice: sip:9996104671@sip.tropo.com
Jabber: saghul_test2@tropo.im

Happy Tropo-ing!

:wq