This has already cost me many hours of Googling and I still cannot get it working, time to ask SO for help :-)
I try to put together a simple test application where the frontend is written in Pyjamas, the backend is running on Web.py. They are supposed to talk to each other via JSON-RPC. The desired functionality is to let the user enter a string which is then converted to uppercase.
There is a description in the Pyjamas online book "Rest of the World" on how to use JSON-RPC which presents various technologies mixed together and is therefore difficult to parse. By looking at hints e.g. from Amund Tveit's blog etc. I cobbled together the following:
1) The server script which is really simple:
import web
import json
import os
urls = (
'/json', 'JSONHandler',
'/json/', 'JSONHandler',
)
app = web.application(urls, globals())
class JSONHandler:
def json_upper(self,args):
return [args[0].upper()]
def json_markdown(self,args):
return [args[0].lower()]
def POST(self):
args = json.loads(web.data())
print args
json_func = getattr(self, 'json_%s' % args[u"method"])
json_params = args[u"params"]
json_method_id = args[u"id"]
result = json_func(json_params)
# reuse args to send result back
args.pop(u"method")
args["result"] = result[0]
args["error"] = None # IMPORTANT!!
web.header("Content-Type","text/html; charset=utf-8")
return json.dumps(args)
if __name__ == "__main__":
app.run()
and it definitely works, tested with a simple query script (not shown) that relies on Josh Marshall's JSON-RPC library.
2) The client-script for Pyjamas which is also straightforward:
# Client example from Amund Tveit's blog
# http://amundblog.blogspot.co.at/2008/12/ajax-with-python-combining-pyjs-and.html
# note: ui and JSONService were not prefixed with pyjamas, but that's needed
from pyjamas.ui import RootPanel, TextArea, Label, Button, HTML, VerticalPanel, HorizontalPanel, ListBox
from pyjamas.JSONService import JSONProxy
class Client:
def onModuleLoad(self):
self.TEXT_WAITING = "Waiting for response..."
self.TEXT_ERROR = "Server Error"
# This is the remote service
self.remote_server = UpperService()
self.status=Label()
self.text_area = TextArea()
self.text_area.setText(r"Please uppercase this string")
self.text_area.setCharacterWidth(80)
self.text_area.setVisibleLines(8)
self.button_py = Button("Send to Python Service", self)
buttons = HorizontalPanel()
buttons.add(self.button_py)
buttons.setSpacing(8)
info = r'Upper-case a string using JSON-RPC'
panel = VerticalPanel()
panel.add(HTML(info))
panel.add(self.text_area)
panel.add(buttons)
panel.add(self.status)
RootPanel().add(panel)
def onClick(self, sender):
self.status.setText(self.TEXT_WAITING)
text = self.text_area.getText()
# (data, response_class): if the latter is 'self', then
# the response is handled by the self.onRemoteResponse() method
if self.remote_server.upper(self.text_area.getText(), self) < 0:
self.status.setText(self.TEXT_ERROR)
def onRemoteResponse(self, response, request_info):
self.status.setText(response)
def onRemoteError(self, code, message, request_info):
self.status.setText("Server Error or Invalid Response: ERROR " + code + " - " + message)
# AJAX calls must come from the same server, only the path is given here
class UpperService(JSONProxy):
def __init__(self):
JSONProxy.__init__(self, "/json/", ["upper"])
I compiled it with PyJs, renamed the default output
directory to static
so that web.py can serve it, edited static/Client.html
so that the internal references point to static
:
<html>
<!-- auto-generated html - You should consider editing and adapting this
to suit your requirements. No doctype used here to force quirks mode; see
wiki for details: http://pyjs.org/wiki/csshellandhowtodealwithit/
-->
<head>
<title>Client (Pyjamas Auto-Generated HTML file)</title>
<meta name="pygwt:module" content="/static/Client"> <!-- was content="Client" -->
</head>
<body style="background-color:white">
<script type="text/javascript" src="/static/bootstrap.js"></script> <!-- was src="bootstrap.js" -->
<iframe id="__pygwt_historyFrame" style="display:none;"></iframe>
</body>
</html>
... and then pointing the browser to http://localhost:8080/static/Client.html
. All I get is a blank page, inspecting the page source shows static/Client.html
above so it was indeed served to the browser. The server's log also shows that at least some pages have been served:
http://0.0.0.0:8080/
127.0.0.1:61466 - - [14/Mar/2013 13:59:39] "HTTP/1.1 GET /static/Client.html" - 200
127.0.0.1:61466 - - [14/Mar/2013 13:59:40] "HTTP/1.1 GET /static/Client.nocache.html" - 200
127.0.0.1:61466 - - [14/Mar/2013 13:59:40] "HTTP/1.1 GET /static/Client.safari.cache.html" - 200
No indication of what went wrong, however. Tried all sorts of other combinations of URLs, renaming directories, compiling the Pyjamas part with the -d option in the hope to get a debug stack trace ... to no avail.
Has anyone succeeded in getting Pyjamas and Web.py working together? If yes, then please share how. Thanks.
PS: I am using web.py V0.37 and the latest Pyjamas development release. (The current stable release V0.8.1 does not work either.)