Thursday, October 3, 2013

PythonScript - Wrapping Javascript Libraries


Wrapping THREE.js

Wrapping Javascript libraries in PythonScript is a simple and direct procedure, using the JS(string) function you can directly inline javascript. The example below wraps the THREE.Vector3 class, in the __init__ constructor it directly calls new THREE.Vector3(x,y,z) and assigned it to self._vec.
class Vector3:
 def __init__(self, x=0, y=0, z=0 ):
  self._vec = JS('new THREE.Vector3(x,y,z)')

 @property
 def x(self):
  vec = self._vec
  return JS('vec.x')
 @x.setter
 def x(self, value):
  vec = self._vec
  JS('vec.x=value')

 @property
 def y(self):
  vec = self._vec
  return JS('vec.y')
 @y.setter
 def y(self, value):
  vec = self._vec
  JS('vec.y=value')

 @property
 def z(self):
  vec = self._vec
  return JS('vec.z')
 @x.setter
 def z(self, value):
  vec = self._vec
  JS('vec.z=value')

@property

The example wrapper above is using the @property decorator to expose the vector x,y,z attributes from Javascript to PythonScript. This was previously not supported by PythonScript, you can see my commit here that adds basic support for getter/setter property decorators.

The python_to_pythonjs compiler was modified to support the @property decorator by inserting the right calls for each instance of a class where those properties get used. This requires that the compiler knows what class type each instance is - this becomes a problem for scripts that are later compiled in another pass, because the compiler needs all the information that was introspected during AST traversal. To workaround this problem the introspected data is dumped to a file for each wrapper module and is loaded later when a script calls: from some_module import *

tests/server.py

I also added a test server, see this commit, using the Tornado web framework that dynamically converts html files that contain embedded PythonScript. It will process any PythonScript wrappers in the head and cache the AST introspection data so that the embedded PythonScript can properly import and use the wrapper classes in them.

Example


<html><head>
<script src="pythonscript.js"></script>
<script src="libs/three/three.min.js"></script>
<script src="bindings/three.py"></script>

<script type="text/python" closure="true">
from three import *

def test():
 v = Vector3(1, 2, 3)
 print( v.x )
 print( v.y )
 print( v.z )

</script>
</head>

<body>
<button onclick="test()">click me</button>
</body>
</html>

No comments:

Post a Comment