2009-06-28
Pyjamas, in the most basic of terms, is a port of the Google Web Toolkit (which uses Java), to Python. What does this really mean? according to the Pyjamas website: pyjamas is a stand-alone python to javascript compiler, an AJAX framework / library and a Widget set API.

With Pyjamas, a developer can write a Python application that contains buttons, labels, and various other common widgets; and then compile the application to a web ready pile of javascipt code. Since the javascript code handles all of the cross-browser crap, the developer can focus on writing a decent app and not have to worry about all of the various browser idiosyncrasies.

As an example, I have created a very basic Pyjamas app that will do the following:

The python code is
from pyjamas.ui.RootPanel import RootPanel from pyjamas.ui.Panel import Panel from pyjamas.ui.VerticalPanel import VerticalPanel from pyjamas.ui.HorizontalPanel import HorizontalPanel from pyjamas.ui.HTML import HTML from pyjamas.HTTPRequest import HTTPRequest from pyjamas.ui.Label import Label from pyjamas.ui.ListBox import ListBox #what do we need to process returned XML? #make a XMLHTTPRequest handler to process the dictionary XML class processDictionaryXMLHandler:     def __init__(self,caller):         #who called this class? (AKA parent)         self.caller caller     def onCompletion(selfxml):         self.caller.set_message("processing data...")         '''process the text'''         elements xml.getElementsByTagName("element")         for in range(elements.length ):             element elements.item(i)             word self.getChildNodeValue(element,"word")             desc self.getChildNodeValue(element,"desc")             self.caller.add_dictionary_item(word,desc)             self.caller.set_message("Adding "+word)         self.caller.update_list()         self.caller.set_message("")     def onError(selftextcode):         self.caller.set_message("error %s %s"  % (code,text))     def onTimeout(selftext):         self.caller.set_message("timeout %s"  text)     #get the value of a nodes child     def getChildNodeValue(self,node,childname):         childNode=node.getElementsByTagName(childname).item(0)         if childNode.firstChild.nodeValue != null:             value childNode.firstChild.nodeValue         else:             value=""         return value     #get the value of a node     def getNodeValue(self,node):         value node.firstChild.nodeValue         return value #define devils dictionary application class class ddApplication:     def __init__(self):         '''make some global variables'''         #we need a dict type to hold key/value pairs for words         self.words_dict = {}         #create a vertical panel to hold most of our infoself.vPan = verticalPanel()         self.vPan VerticalPanel()         #make a label for "devils dictionary         title Label("The Devil's Dictionary (L through Z)")         #give credit to the author         by Label("by Ambrose Bierce")         #give titles to the labels so we can style them with a CSS         title.setStyleName("dd_title")         by.setStyleName("dd_by")         #add the labels to the vertical panel         self.vPan.add(title)         self.vPan.add(by)         #create a listbox to display the words         self.wordsListBox ListBox()         #make the wordslistbox a dropdownlist         self.wordsListBox.setVisibleItemCount(20)         #hide the wordslistbox         self.wordsListBox.setVisible(False)         #what should happen when the wordslistbox changes?         self.wordsListBox.addChangeListener(getattr(self,"word_list_changed") )         #add the wordsListBox to the vertical panel         #self.vPan.add(self.wordsListBox)         #make an HTML text thingy to hold the definition of the word         self.definitionHTML HTML("")         #hide the definition         self.definitionHTML.setVisible(False)         #add the definition to the vert panel         #self.vPan.add(self.definitionHTML)         hPan HorizontalPanel()         #add some spacing for the hPan elements         hPan.setSpacing(10)         hPan.add(self.wordsListBox)         vPan2 VerticalPanel()         self.wordLabel Label("")         vPan2.add(self.wordLabel)         vPan2.add(self.definitionHTML)         hPan.add(vPan2)         self.vPan.add(hPan)         #make a label to pass messages to the user in case of a problem         self.messageLabel Label()         #set the style for the messageLabel         self.messageLabel.setID("info_label")         #add the messageLabel to the vert panel         self.vPan.add(self.messageLabel)         #add the vertical panel to a specific div of the template         RootPanel("content").add(self.vPan)     def word_list_changed(self):         #get the current index of the wordslistbox         selected_index self.wordsListBox.getSelectedIndex()         word self.wordsListBox.getValue(selected_index)         self.display_definition(word)              def set_message(self,message):         self.messageLabel.setText(message)              def display_definition(self,word):         self.wordLabel.setText(word)         definition self.words_dict[word].strip()         self.definitionHTML.setHTML("<pre>"+definition+"</pre>")         self.definitionHTML.setVisible(True)     def add_dictionary_item(self,word,description):         self.words_dict[word]=description              def update_list(self):         for key in self.words_dict.keys():             self.wordsListBox.addItem(key)         #display the wordListBox         self.wordsListBox.setVisible(True)     def run(self):         self.get_dictionary_xml()     def get_dictionary_xml(self):         self.set_message("retrieving XML data...")         HTTPRequest().asyncGet(None,None,"dictionary.xml",processDictionaryXMLHandler(self),1); if __name__ == '__main__':     app ddApplication()     app.run()

Looks like a typical Python app to me!

The compiled web application is viewable at www.jezra.net/code_examples/pyjamas_devil/index.htm

As with most things, there were a few gotcha's that I ran into and I had a devil of a time finding the solutions. The first, and in my mind the most important gotcha is that when making an HTTPRequest().asyncPost(), one needs to add "1" as the last argument if the returned data is XML. If the "1" is omitted, the returned data is treated as plain text and any attempt to process the data as XML will fail.

The second biggest gotcha also deals with XML. Since there is no discernable documentation for processing data from returned XML, one might need to write custom functions, based on the few available Pyjamas examples that deal with HTTPRequests, for retrieving data from a chunk of XML. Although this isn't really that major of an issue, but it would be more efficient to use native XML processing and not have to reinvent the wheel.

All things considered, I certainly plan to use Pyjamas in the future whenever I need to write an asyncronous web-app.
Comments
2010-08-21 Rick:
I'm not sure what you mean by "retrieving data from a chunk of XML", but this sounds like some sort of parsing to me and in my opinion this doesn't belong on the client side, javascript is a quirky weird langauge for doing "real programming stuff" as I have found at times in the past, you should use the server side python for any parsing like this and have it send the data to the client side in as controlled a manner as possible, just trying to make javascript (its still converted to javascript at the end from your python code) parse random XML, etc sounds like a recipe for disaster to me
2010-08-21 jezra:
Rick, I was indeed referring to XML processing, which I've never really like in any language. However, by transferring data as XML, the data is being formatted and transferred in a very controlled manner and this allows me to programmatically retrieve the data that I need.
Name:
not required
Email:
not required (will not be displayed)
Website:
not required (will link your name to your site)
Comment:
required
Please do not post HTML code or bbcode unless you want it to show up as code in your post. (or if you are a blog spammer, in which case, you probably aren't reading this anyway).
Prove you are human by solving a math problem! I'm sorry, but due to an increase of blog spam, I've had to implement a CAPTCHA.
Problem:
7 minus 6
Answer:
required
  • Tags:
  • Python
subscribe
 
2019
2016
2015
2014
2013
2012
2011
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008