Issues with Pyjamas/en

De Goffiwiki
Aller à : navigation, rechercher

Issues with Pyjamas

You should not expect the JavaScript code produced by Pyjamas to exactly work as in Python. Some things to take care about:

  • no unicode class
 unicode = str  # FIXME: pyjamas workaround
  • JID class is partly implemented in, and the attributes 'node', 'domain' and 'resource' should only be accessed, never modified because the JID itself will not be updated! If you want to modify one of these attributes, it's a bit annoying but you must build a new JID instance:
 contact_jid = jid.JID("")
 contact_jid.resource = 'work'
 print contact_jid  # will display ''
 new_jid = jid.JID("%s/%s" % (unicode(contact_jid.bare), 'work')
 print contact_jid  # will display '' as expected
  • Since our JID class for Pyjamas doesn't inherit from a base type (unicode), the list membership test is done via object references. To reproduce the twisted behavior (i.e. to check the object value and not its reference), we need a special class JIDList to overwrite the __contains__ method.
  • property decorator setter doesn't works well, you should really avoid it
  • property decorator getter usually works, but be careful when you use it in the middle of an expression. For example, if you need to get a property and then call one of its method, you must use a temporary variable to get the property first and call the method afterward. If you don't need to call a method but just get a "normal" attribute, it works OK.
 # x is a property of obj
 obj.x.color  # works
 obj.x.color()  # doesn't work
 x = obj.x
 x.color()  # works!
  • Calling hash on a class method always return a different value if that method is defined directly within the class (with the "def" keyword). So you can't rely on the "in" operator to test the appartenance in a list. The "==" operator will also not give the expected value, so you can't use it directly on the method. You can get the expected behavior by making an indirection with a class attribute referencing the method.
 class X(object):
   def __init__(self):
     self.y = self.x
     hash(self.x) == hash(self.x)  # False
     hash(self.y) == hash(self.y)  # True
     self.x == self.x  # False
     self.y == self.y  # True 
   def x(self):
  • cls attribute in a class method couldn't be used to instanciate a new object, you have to write down the class name instead
  • depending of the options you used to compile with pyjsbuild, you will sometimes get a TypeError instead of an AttributeError
  • casting a list to a set doesn't work if the None value is in the list (some other issues might happen when None is in a list)
  • the count method of list objects is not implemented
  • del to delete an entry from a dictionary doesn't raise any error when the key doesn't exist, so it's better to always use pop:
 x = {}
 del x["key"]  # Python does raise an error but Pyjamas doesn't
 x.pop("key")  # both Python and Pyjamas raise here a KeyError
  • there are some issues with pyjsbuild --strict option, for example multiple inheritance won't work. You can use "--strict" on certain circumstances to debug something but it is not recommended to have it always.
  • you can not define a class that inherates from a base type such as str
  • avoid using __getattr__, __class__ and such attributes
  • you can not take benefit of super to deal with multiple inheritance. Have a look at these examples to understand the issue:
 # example 1 not using super in the parent classes
 class A(object):
     def __init__(self):
         print "A"
 class B(object):
     def __init__(self):
         print "B"
 class C(A, B):
     def __init__(self):
         super(C, self).__init__()
 C()  # will display only 'A', in both Python console and Pyjamas
 # example 2 using super everywhere
 class A(object):
     def __init__(self):
         super(A, self).__init__()
         print "A"
 class B(object):
     def __init__(self):
         super(B, self).__init__()
         print "B"
 class C(A, B):
     def __init__(self):
         super(C, self).__init__()
 C()  # will display 'B' and 'A' in Python console, but only 'A' in Pyjamas
  • Be careful when calling a method that uses embedded javascript code to return a value. For example:
 def getFileInfo(self):
     from __pyjamas__ import JS
     JS("var file = top.document.getElementById(this._id).files[0]; return [file.size, file.type]")
 def getFileSize(self):
     return self.getFileInfo()[0]

Calling getFileSize will fail (at least on Firefox with debug mode) with:

 TypeError: (intermediate value)(...).__getitem__ is not a function

The solution is to use the following workaround:

 def getFileSize(self):
     size, filetype = self.getFileInfo()
     return size

Other issues related to the Pyjamas library (pyjamas.ui):

  • setStyleName with MenuBar object doesn't work, it sets the instance string representation instead of the CSS class
  • FlowPanel is not fully implemented yet and can't be used with Label
  • self.currentEvent is sometimes not set when it should be (for example in TextBox.onBrowserEvent and as a consequence the cancel key doesn't work)
  • AutoCompleteTextBox.visible is not set to False when ENTER is pressed and a completion is done
  • we saw already that super is not well implemented and you can't benefit from it to deal with multiple inheritance, but also the pyjamas.ui classes don't use super themselves. So even if the pyjsbuild compiler was doing well with super, you would need to change the library for super to be used everywhere (the previous examples show that when you use super once, you need to use it everywhere).
  • In some cases, Pyjamas' re module gets crazy and freeze the browser. Therefore it is recommended to avoid re and use Python's string.replace or a native javascript implementation instead. Methods from quick_frontend that use re should be overwritten (see for example libervia.browser.sat_browser.strings.addURLToText).

Other issues related to pyjsbuild which have nothing to do with Python:

  • pyjamas hacks the Python import to allow the import of JS files, but the import order will be messed up if you import more than one JS file from the same Python file. Also, the imported file needs to be in the compilation directory (no sub-module). Finally, the imported file must end with a empty line or semi-column.