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.
You, the Python developer, use Python because you want to, but in the browser you use JavaScript because you think you have to. With IronPython you can write browser code in Python. I’ll only begin to answer "what can the browser bring to Python?" and "what can Python bring to the browser?" in this short overview; examples will be very simple (with the exception of a few flashy ones) to make sure you can get started immediately.
Follow along
Also, all information and documentation about this can be found the new ironpython.net/browser page:
Setting Expectations
“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.
Hello, World
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:
Though, I’d strongly suggest against writing any real app with your python inline with HTML, as it then can’t be reused. Sticking your python code in a .py file and referencing it from a script-tag is preferred for separation-purposes.
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:
Note: you have repl.py locally if you downloaded the demos, or point to the online one directly.
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:
How all this works
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.
To allow Python to be indented inside a script tag, the margin of the first line which does not only contain whitespace is removed. Line numbers in the HTML are preserved, so error messages show up correctly:
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.
For more information how how this all works, see the paper and the source code. Also, for more information on the DLR, see the DLR docs page.
Batteries included here too
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.
The Python standard library is a little less than 5MB compressed, so it's not unthinkable to include the whole thing for development, but for deployment you should just include the dependencies; unittest's dependencies are 58 KB.
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("repl.py")
, or open("PythonStdLib/unittest.py")
would also work.
For anyone familiar with the older XAP-file/Chiron-based way to build Silverlight apps with IronPython: this combined script-tag/zip-file file-system abstraction is what allows you to never need to put file in the main application's XAP.
Another interesting library to in Silverlight is rst2xaml, which takes any reStructuredText-formatted files and converts them to XAML to be rendered in Silverlight.
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:
Source code summarized from both mandelbrotbase.cs and mandelbrot.py
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:
Webcam usage requires Silverlight 4 Beta; you can download the installer for mac or windows.
Tooling
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:
Conclusion
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!