Quantcast
Channel: Hacker News 50
Viewing all articles
Browse latest Browse all 9433

SheetJS Rants and Raves — Running your JS code in Python

$
0
0

Comments:"SheetJS Rants and Raves — Running your JS code in Python"

URL:http://blog.sheetjs.com/post/71326534924/running-your-js-code-in-python


tl;dr: PyPI package xls (repo https://github.com/SheetJS/py-xls)

I wanted to see if it was possible to run the JS XLS module from Python, partially because I needed an XLS parser in a python tool but mostly to prove to myself that it can be done.

Running small fragments of JS is easy with PyV8:

$ sudo pip install PyV8
$ python
>>> import PyV8
>>> ctx = PyV8.JSContext()
>>> ctx.enter()
>>> ctx.eval('1+1')
2

Variables are available:

>>> ctx.eval('var x = 1+1')
>>> ctx.eval('Math.pow(x,x)')
4

However, the context is bare bones.  Even the mighty console is missing

>>> ctx.eval('console.log(x)')
ReferenceError: ReferenceError: console is not defined ( @ 1 : 0 ) -> console.log(x)

Fortunately, you can configure the context with your own console:

class MyConsole(PyV8.JSClass):
def log(self, *args):
print(" ".join([str(x) for x in args]))

class GlobalContext(PyV8.JSClass):
console = MyConsole()

ctx = PyV8.JSContext(GlobalContext())

… which works as expected:

>>> ctx.enter(); ctx.eval('console.log("foo bar baz qux")')
foo bar baz qux

For larger scripts, I found it easy to just put the entire code block within a triple-quoted string.  The only caveat is that slashes have to be escaped.  To automate the process, the code is separated into a python header and footer, with a Makefile to bring everything together. (note: the header ends with a triple quote and the footer starts with a triple quote)

In python code, you can access the variables in the JS scope with ctx.locals[‘…’], and numbers are readily available:

>>> ctx.eval('x = 1+1')
2
>>> ctx.locals['x']
2

however, arrays are passed as JSArray.  The easiest way to capture the python values is to slice the array:

>>> ctx.eval('y = [1,2]')
<_PyV8.JSArray object at 0x106ebc5f0>
>>> ctx.locals['y']
<_PyV8.JSArray object at 0x106b82050>
>>> ctx.locals['y'][:]
[1, 2]

PyV8 automatically converts numeric and string literals from python to JS form, making it a breeze to call functions:

>>> ctx.eval('z=function(foo,bar) { return foo+bar; }')
>>> ctx.locals['z'](1,2)
3

I suspect it would be possible to build up a wrapper that emulates the entire NodeJS javascript API in PyV8, making it easy for people to bring pure-JS modules into Python.  But that’s a task for another day.


Viewing all articles
Browse latest Browse all 9433

Trending Articles