view docs.html @ 24:c2c369402a2e

Added more docs, fixed edge cases.
author Atul Varma <varmaa@toolness.com>
date Thu, 10 Sep 2009 22:32:45 -0700
parents 7cbbec55aef6
children 351819baecd1
line wrap: on
line source

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.4: http://docutils.sourceforge.net/" />
<title>Pydertron</title>
<link rel="stylesheet" href="docs.css" type="text/css" />
</head>
<body>
<div class="document" id="pydertron">
<h1 class="title">Pydertron</h1>
<p>Pydertron is a high-level wrapper for <a class="reference" href="http://code.google.com/p/pydermonkey">Pydermonkey</a> that
provides convenient, secure object wrapping between JS and Python
space.</p>
<p>Note that Pydertron is just one example of a high-level interface
between Python and JavaScript: it assumes, for instance, that the JS
code it executes isn't trusted, which affects the nature of the
inter-language interaction.</p>
<div class="section">
<h1><a id="the-basics" name="the-basics">The Basics</a></h1>
<p>The <tt class="docutils literal"><span class="pre">JsSandbox</span></tt> class encapsulates a JavaScript runtime, context, global
object, and a simple <a class="reference" href="http://wiki.commonjs.org/wiki/CommonJS/Modules/SecurableModules">SecurableModule</a> implementation that complies
with the <a class="reference" href="http://wiki.commonjs.org/wiki/CommonJS">CommonJS</a> 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.</p>
<p>For instance, here we'll create a <tt class="docutils literal"><span class="pre">JsSandbox</span></tt> whose module root
points to the <a class="reference" href="http://interoperablejs.googlecode.com/svn/trunk/compliance/monkeys/">monkeys</a> SecurableModule compliance test over HTTP:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; url = (&quot;http://interoperablejs.googlecode.com/svn/trunk/&quot;
...        &quot;compliance/monkeys/&quot;)
&gt;&gt;&gt; sandbox = JsSandbox(HttpFileSystem(url))
</pre>
</blockquote>
<p>This compliance test requires a global <tt class="docutils literal"><span class="pre">sys</span></tt> object that contains one
method, <tt class="docutils literal"><span class="pre">print()</span></tt>, that takes two arguments. First, we'll create the
<tt class="docutils literal"><span class="pre">print()</span></tt> function and prepare it for exposure to JS code:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; &#64;jsexposed
... def jsprint(message, label):
...   print message, label
</pre>
</blockquote>
<p>Note the use of the <tt class="docutils literal"><span class="pre">&#64;jsexposed</span></tt> decorator: all this does is set
the function's <tt class="docutils literal"><span class="pre">__jsexposed__</span></tt> attribute to <tt class="docutils literal"><span class="pre">True</span></tt>. 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.</p>
<p>Creating a JS object can be done like this:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; system = sandbox.new_object()
</pre>
</blockquote>
<p>We can now access and set properties on this object via either
item or attribute lookup, just like in JavaScript. Because
<tt class="docutils literal"><span class="pre">print</span></tt> is a reserved word in Python, though, we'll use item
lookup to set the property here:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; system['print'] = jsprint
</pre>
</blockquote>
<p>Now we tell the sandbox that we want the <tt class="docutils literal"><span class="pre">sys</span></tt> object to be a
global:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; sandbox.set_globals(sys = system)
</pre>
</blockquote>
<p>And finally, we execute the compliance test by running a one-line
script that imports the 'program' module, like so:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; sandbox.run_script(&quot;require('program');&quot;)
PASS monkeys permitted pass
DONE info
0
</pre>
</blockquote>
<p>Note the <tt class="docutils literal"><span class="pre">0</span></tt> in the last line: this is the return value of
<tt class="docutils literal"><span class="pre">sandbox.run_script()</span></tt>, which returns <tt class="docutils literal"><span class="pre">0</span></tt> on success, and
<tt class="docutils literal"><span class="pre">-1</span></tt> if an exception was raised. For instance, the output of bad
code looks like this:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; sandbox.run_script(&quot;(function foo() { bar(); })();&quot;,
...                    stderr=sys.stdout)
Traceback (most recent call last):
  File &quot;&lt;string&gt;&quot;, line 1, in &lt;module&gt;
  File &quot;&lt;string&gt;&quot;, line 1, in foo
ReferenceError: bar is not defined
-1
</pre>
</blockquote>
<p>Note that the traceback displayed is actually referring to JavaScript
code: one of Pydertron's aims is to make debugging JS code as much
like debugging Python code as possible.</p>
</div>
<div class="section">
<h1><a id="exceptions" name="exceptions">Exceptions</a></h1>
<p>Any exceptions raised by wrapped Python functions need to be of type
<tt class="docutils literal"><span class="pre">pydermonkey.error</span></tt> to be propagated into calling JavaScript code;
if they're not, then for security purposes, the entire JavaScript call
stack is unrolled.</p>
<p>For example, here's a function that's bound to fail:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; &#64;jsexposed
... def fail():
...   o()
&gt;&gt;&gt; sandbox.root.fail = fail
</pre>
</blockquote>
<p>Now, even though the following JS code calls the function in a
try-catch block, the JS code doesn't catch anything and its execution
is simply halted:</p>
<blockquote>
<pre class="doctest-block">
&gt;&gt;&gt; sandbox.run_script(&quot;try { fail(); } catch (e) {}&quot;,
...                    stderr=sys.stdout)  #doctest: +ELLIPSIS
An internal error occurred.
Traceback (most recent call last):
...
NameError: global name 'o' is not defined
-1
</pre>
</blockquote>
<p>Note that a <tt class="docutils literal"><span class="pre">KeyboardInterrupt</span></tt> triggered while JS is executing will
have similar effect.</p>
</div>
</div>
<div class="footer">
<hr class="footer" />
<a class="reference" href="docs.txt">View document source</a>.

</div>
</body>
</html>