# HG changeset patch # User Atul Varma # Date 1252622658 25200 # Node ID d382ca63d43fe1dd04947f0372808376d9c6b40f # Parent 2dc43c316df9cb5f872938af10c381eab27371e8 Added docs with doctests. diff -r 2dc43c316df9 -r d382ca63d43f pydertron.py --- a/pydertron.py Thu Sep 10 15:13:33 2009 -0700 +++ b/pydertron.py Thu Sep 10 15:44:18 2009 -0700 @@ -37,6 +37,75 @@ """ 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 "", line 1, in + File "", 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. """ import sys @@ -562,11 +631,14 @@ return self.__modules[filename] def run_script(self, contents, filename='', lineno=1, - callback=None, stderr=sys.stderr): + callback=None, stderr=None): """ Runs the given JS script, returning 0 on success, -1 on failure. """ + if stderr is None: + stderr = sys.stderr + retval = -1 cx = self.cx try: diff -r 2dc43c316df9 -r d382ca63d43f test_docs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test_docs.py Thu Sep 10 15:44:18 2009 -0700 @@ -0,0 +1,6 @@ +import doctest + +import pydertron + +if __name__ == '__main__': + doctest.testmod(pydertron, verbose=True)