Pydertron

Pydertron is a high-level wrapper for Pydermonkey that provides convenient, secure object wrapping between JS and Python space.

The JsSandbox class encapsulates a JavaScript runtime, context, global object, and a simple SecurableModule implementation that complies with the CommonJS standard. It also provides a high-level bridge between Python and JavaScript so that you don't need to deal with any of the low-level details of the Pydermonkey API.

For instance, here we'll create a JsSandbox whose module root points to the monkeys SecurableModule compliance test over HTTP:

>>> url = ("http://interoperablejs.googlecode.com/svn/trunk/"
...        "compliance/monkeys/")
>>> sandbox = JsSandbox(HttpFileSystem(url))

This compliance test requires a global sys object that contains one method, print(), that takes two arguments. First, we'll create the print() function and prepare it for exposure to JS code:

>>> @jsexposed
... def jsprint(message, label):
...   print message, label

Note the use of the @jsexposed decorator: all this does is set the function's __jsexposed__ attribute to True. This is done for security purposes: only Python callables satisfying this criteria will be exposed to JavaScript code, to ensure that untrusted JS can't accidentally gain access to privileged Python functionality.

Creating a JS object can be done like this:

>>> system = sandbox.new_object()

We can now access and set properties on this object via either item or attribute lookup, just like in JavaScript. Because print is a reserved word in Python, though, we'll use item lookup to set the property here:

>>> system['print'] = jsprint

Now we tell the sandbox that we want the sys object to be a global:

>>> sandbox.set_globals(sys = system)

And finally, we execute the compliance test by running a one-line script that imports the 'program' module, like so:

>>> sandbox.run_script("require('program');")
PASS monkeys permitted pass
DONE info
0

Note the 0 in the last line: this is the return value of sandbox.run_script(), which returns 0 on success, and -1 if an exception was raised. For instance, the output of bad code looks like this:

>>> sandbox.run_script("(function foo() { bar(); })();",
...                    stderr=sys.stdout)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1, in foo
ReferenceError: bar is not defined
-1

Note that the traceback displayed is actually referring to JavaScript code: one of Pydertron's helpful conveniences is that it makes debugging JS code as much like debugging Python code as possible.