0

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.)

András Aszódi
  • 8,948
  • 5
  • 48
  • 51

1 Answers1

1

I know you're probably over this, but finding your code helped me fixing mine and it seems tricky to find working examples online for pyjs with webpy.

Your problem was on the client script side, where you needed to add some code to start the client:

if __name__ == '__main__':
    app = Client()
    app.onModuleLoad()

Moreover, to avoid errors that will then appear, your first line of import should be changed to:

from pyjamas.ui.RootPanel import RootPanel
from pyjamas.ui.TextArea import TextArea
from pyjamas.ui.Label import Label
from pyjamas.ui.Button import Button
from pyjamas.ui.HTML import HTML
from pyjamas.ui.VerticalPanel import VerticalPanel
from pyjamas.ui.HorizontalPanel import HorizontalPanel
from pyjamas.ui.ListBox import ListBox
Vorty
  • 61
  • 4
  • Many thanks for your response! I now get the input panel rendered nicely. It sends the request, then waits for the answer indefinitely... so there's something else missing from my setup. Anyway, +1 for you! – András Aszódi Jun 19 '13 at 15:35