Last weekend I was very fortunate to speak at PyCon 2010 in Atlanta about writing browser-based applications in Python. A majority of the IronPython team was also there; Dino Viehland spoke about IronPython Tooling in a keynote slot, Dave Fugate gave a poster presentation about testing IronPython, and Bill Chiles was there for emotional support. It was also great to see Michael Foord, and also see how supportive the Python community is of IronPython.
Here’s the write-up from my talk:
Introductions and talk overview
I primarily work on IronRuby, but when it comes to web technologies I give IronPython love as well. Actually, I was an intern back when it was just the IronPython team, and when I started full-time I was doing exactly what this talk is about -- getting Python running in the browser -- so I'm really excited to be talking about this at PyCon.
Also, all information and documentation about this can be found the new ironpython.net/browser page:
“Python in the browser” is not Microsoft embracing and extending the browsers to support Python. In fact, this integration downloads python on demand, so there is no change required to the browser This is because Silverlight as the Python execution engine …
… and if you’re wondering “What is Silverlight?” …
Silverlight is a browser plug-in for Windows, and Mac OS (Novell makes a Linux version called “Moonlight”), which provide a managed execution engine for .NET-based programming languages in the browser, a rich set of vector-graphics-based UI features, and interop with the browser programming model and DOM. Go to http://silverlight.net for more information.
Let's start with the latter, and show the most obvious thing Python can bring to the browser: Python.
To develop a Python application in the browser, you just need your favorite text editor; so open it up, create a HTML file, reference
dlr.js, and then you can use script-tags for running Python code:
And the Python code does what you'd expect:
Simple, right? Let's do something slightly more complicated, like handling mouse clicks. I'd prefer to do this in a REPL window, so let's turn one on in the browser; just place the following script-tag in the page:
And now when you add
?console to the page's URL a Python repl window will appear:
The console is hooked up to
sys.stdout, so your existing text-based Python scripts can come alive in the browser (sans reading from stdin). Also, any print statements you use in the app will show up in the console as well, making it a great println-debugging tool.
Let's play around with the page a bit, adding a DOM element and changing it's HTML content to "Ouch!" when clicked:
Wow, Python works in the browser! Let's look behind the curtain for a second to see what is really going on.
dlr.js contains a collection of functions for creating a Silverlight control on the HTML page that is capable of running IronPython code.
By default, just running dlr.js injects a Silverlight
<object> tag into the page (immediately after the script-tag) so it can run only DOM-based scripts, and also scans for other script-tags indicating that you want a Silverlight rendering surface, but more on that later.
The injected Silverlight control points to a Silverlight application made specifically to embed the dynamic language runtime, the compiler/runtime/embedding infrastructure IronPython is built on, find all the Python code the HTML page uses, and executes it.
The XAP is tiny, as the DLR and IronPython are in separate packages which are downloaded on-demand; the DLR and IronPython are not installed with Silverlight, so they must be downloaded with the application.
However, if the application depends on the ironpython.net binaries, the user's browser will cache them and they won't be re-downloaded for any other app; almost as good as being part of the installer, while still being able to be open-source.
Now user-code is able to run. Each inline Python script-tag is executed as if it was one Python module, and all other Python files execute as their own modules.
The code is handed off to the DLR Hosting APIs (in the Microsoft.Scripting.Hosting namespace), which (a bit simplified) looks like this in C#:
Executing Python code with the DLR hosting APIs is very straight-forward; essentially Python-eval for .NET-based languages. This hosting API abstract the “embedding” of Python away from the actual engine, so an application that hosts the DLR can use one API and switch between any language compatible with the DLR.
Great, I can write python code in my browser, but how do I test it?
A powerful part of Python is its standard-library; almost all Python applications depend on it, and it has some really useful libraries, like unittest. Here's a very simple test of the “say_ouch” app:
But where did unittest come from? Take a closer look at the first line:
That zip file contains the pieces of the Python standard-library that unittest depends on.
When a zip file's filename is added to the path, it is treated like any other directory;
import looks inside it to find modules. You'll also notice that
import repl just worked, even though
repl.py isn't in the zip file; it was referenced by a script-tag earlier. It works because script-tags actually represent file-system entries; doing
open("PythonStdLib/unittest.py") would also work.
Using .NET built-in and external APIs
Now let's transition to what the browser can bring to Python; specifically the APIs that Silverlight exposes. Silverlight has a ton of functionality, and as I was only able to discuss a few Python libraries in Silverlight, I'll only be able to show a few Silverlight libraries being used from Python, but the entirety of Silverlight can be used from Python. See all the features Silverlight provides, as well as how to use .NET APIs in-general from Python.
One interesting API is the WritableBitmap, which gives you per-pixel access to render whatever you want. For example, here its used to render a fractal:
Example derived from A.Boschin.
This is even more interesting because the actual bitmap was generated by code written in C#, but called from Python:
As with any computationally-intensive operations, it's a good idea to write them in a static pre-compiled language; for example the scientific-computation libraries for Python are actually written in C, but the library provide an API accessible to Python programmers. Unfortunately, CPython puts that responsibility on the library developer; not every C library can be directly consumed by Python code. However, this example shows that IronPython can call into any C# library, or any library written in a .NET language for that matter. This makes it trivial to just begin writing your application in Python, and then decide to convert the performance-sensitive sections to C#.
Example derived from Tim Heuer’s webcam-mic app
Another interesting use of WritableBitmap is attaching different types of video sources to it, like a webcam! The upcoming version of Silverlight (version 4) supports webcam and microphone capture, and all that can be used from Python:
The IronPython team’s big announcement at PyCon 2010 was the preview-availability of “IronPython Tools”, and add-on for Visual Studio 2010. This release was only distributed to PyCon 2010 attendees on CDs in their swag-bags, with a public release planned for the same time that VS 2010 final is released.
IronPython tools comes with the beginnings of Silverlight support; for starters you can make a new Silverlight project:
IronPython tools uses the DLR hosting APIs for colorizing code:
And using Debug->Attach To Process you can set breakpoints in your python code (even code embedded in the HTML page) and use the Visual Studio debugger to step-through you app:
Now you know …
- What a Python browser app looks like
- What is going on behind the scenes
- How to use real python libs in the browser
- How to use Silverlight APIs from Python
- That there is a prototype of IronPython tooling!