Sunday, February 26, 2012

Fun with Python for iOS

So, a Python environment for iOS has been released. Unfortunately, it doesn't provide a way to import code. This more or less renders it a toy, right? Well, not quite!
It does provide both exec and urllib, so I wrote a little script to load libraries on it. The script works by creating modules with exec, putting them in sys.modules, and attempting to emulate the behaviour of Python's own module loading. Currently, the module must be specced in the following format:
('web',
        'utils',
        'net',
        'webapi',
        'http',
        'httpserver',
        'wsgi',
        'db',
        'template',
        'debugerror',
        'form',
        'session',
        'application',
        'browser',
        ('wsgiserver', '__init__'),
        '__init__'))
However, it would be possible to divine dependencies from the library.
You can see it in action by entering:
import urllib2
exec urllib2.urlopen("http://rsynnott.com/pyios/loadcode.py").read()

load_package('simplejson')

import simplejson
in Python for iOS, or indeed any interpreter. Run that, then enter 'import simplejson', and you have an external library!
For a slightly more interesting example, do
exec urllib2.urlopen("http://rsynnott.com/pyios/loadcodeweb.py")
This will give you web.py (actually a slightly modified version, with __file__ removed from the error page generator, and a minor modification to the wsgiserver to tolerate the module loading scheme), running a hello world app. If you switch to the browser and visit http://localhost:8080, you'll see the page, though it may take a little while to load.
You can see the loader code here.
Having the ability to bring in your own code obviously makes the app far more useful.
Python for iOS (and a few other interpreter environments for iOS) seem to occupy an interesting place as regards the App Store terms of service. You're not allowed, in principle, have an application which downloads and executes code from the web, but obviously in the case where you have an eval equivalent and a HTTP client, the user can do that themselves. In practice, this seems to be largely ignored.