1
=====================================
2
How to use JavaScript backend of PyPy
3
=====================================
8
Maciej Fijalkowski, fijal@genesilico.pl
13
This tutorial explains how to use `PyPy`_'s JavaScript backend. The
14
reader should have some previous knowledge of writing `RPython`_
17
The JavaScript backend lets you write `RPython`_ source code which gets
18
translated into JavaScript and executed in a browser. The resulting
19
JavaScript code should not depend on a browser (this is a backend
20
responsibility) and should integrate as much as possible with a web
23
.. _`PyPy`: http://codespeak.net/pypy
24
.. _`RPython`: http://codespeak.net/pypy/dist/pypy/doc/coding-guide.html#restricted-python
29
You can use a JavaScript backend in many different ways. One of those is
30
to simply run `jscompile`_ from the 'bin' directory with a module name and a
31
list of functions, this makes that the listed functions get compiled. Another
32
way is to use the rpython2javascript function from `js.main`_ to generate
33
your javascript on-the-fly (e.g. when serving a web page).
35
.. _`jscompile`: http://codespeak.net/svn/pypy/dist/pypy/bin/jscompile.py
36
.. _`js.main`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/main.py
38
Here is a simple example using `MochiKit`_'s logDebug call to show a
41
from pypy.translator.js.modules import mochikit
44
mochikit.createLoggingPane(True)
45
mochikit.logDebug("Hello")
47
Save this to a python file, e.g. simpledemo.py. Then use jscompile to
48
create a javascript version::
50
$ python pypy/bin/jscompile.py simpledemo simple_example
52
Note that you specify the module as a python module which must be on the
55
When you run this you should see some information on the compilation
56
process scrolling past. The JavaScript is written to a file which looks
58
`/tmp/usession-1/some_strange_function_which_will_never_be_called.js`.
60
You can call the compilation process programatically using
63
from pypy.translator.js.main import rpython2javascript
67
js_src = rpython2javascript(simpledemo, ["simple_example"])
70
.. _`MochiKit`: http://www.mochikit.com/
71
.. _`rpython2javascript`:
76
The idea is simple: Normal python method calls get rendered as
77
communication over `XMLHttpRequest`_ without too much user intervention.
78
To achieve this, you must tell PyPy that *these* particular method calls
79
need to be rendered in this way.
81
To achieve this, first you must subclass BasicExternal from `bltregistry`_ and
82
provide an instance of it to RPython code (for instance as global variable).
83
Then you need to set class instance's `_render_xmlhttp` to `True`, to tell the
84
JS backend to render it using xmlhttp communication. Because the web server
85
code does not need to be rpython, you have to supply some way of telling PyPy
86
what types can be returned out of it. This is done using the decorator
87
`@callback(retval = <used type>)` from `bltregistry`_. For example you may
90
from pypy.translator.js.lib.support import callback
92
@callback(retval = {str:str})
93
def some_fun(self, some_arg = 3):
96
The decorator tells the compiler that this function will return mapping from
97
string to string and will take integer as an argument. You can simply specify
98
the arguments using keyword arguments with an example, or pass an args
99
dictionary to the described decorator.
101
Then you must supply a method which returns JSON data in the server
102
itself (for example, this is done automatically by `TurboGears`_ using
103
the `@expose(format='json')` decorator).
105
.. _`XMLHttpRequest`: http://en.wikipedia.org/wiki/XMLHttpRequest
106
.. _`TurboGears`: http://www.turbogears.org/
107
.. _`bltregistry`: http://codespeak.net/svn/pypy/dist/pypy/rpython/ootypesystem/bltregistry.py
112
To create a simple javascript method which pings a server you need two parts, a server side python class which knows how to talk via XMLHttpRequest to a client side call.
116
from pypy.rpython.ootypesystem.bltregistry import BasicExternal
117
from pypy.translator.js.lib.support import callback
119
class PingHandler(BasicExternal):
120
_render_xmlhttp = True
122
@callback(retval={str:str})
123
def ping(self, ping_str="aa"):
124
return dict(response="PONG: %s" % ping_str)
126
ping_handler = PingHandler()
128
This uses the BasicExternal class and the described decorator to let PyPy know
129
how to deal with the input and output of the methods. Now you can use an
130
instance of this class to pass to other parts of the RPython code.
132
On the client you call the ping_handler.ping method with a callback::
134
from pypy.translator.js.modules import mochikit
135
from somewhere import ping_handler
137
def callback(response):
138
mochikit.logDebug("Got response: " + response["response"])
141
ping_handler.ping("PING", callback)
143
You compile this to JavaScript using jscompile or rpython2javascript and
144
the ping method. The resulting javascript is passed to a web browser,
145
while there needs to be a server which knows how to deal with a HTTP
146
request to `/ping` (the name is derived from the name of the method
147
decorated with described). The server then calls the `ping_handler.ping`
148
method with the data from the call and returns a JSON dictionary.
150
Integration with TurboGears or any other web framework:
151
-------------------------------------------------------
153
There is nothing special in this case. The JS backend can work with
154
virtually any web framework. In some of the examples TurboGears is used,
155
but just for simplifying generation of the JSON data. You can use
156
`simplejson`_ to generate a JSON response from any framework. The `django ping example`_ shows how to do this in `Django`_.
158
.. _`simplejson`: http://cheeseshop.python.org/pypi/simplejson
159
.. _`Django`: http://www.djangoproject.com/
164
There is bub'n'bros client working in javascript available `here`_ (No
165
working copy on-line right now, sorry) and a simple example of JS a
166
`python console`_. There is also a simple `django ping example`_.
168
.. _`here`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/bnb/start_bnb.py
169
.. _`python console`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/pythonconsole.py
170
.. _`django ping example`: http://codespeak.net/svn/pypy/dist/pypy/translator/js/examples/djangoping