TL; DR: v8.py
PyMiniRacer brings a compiled V8 interpreter and a simple interface to the Python community:
The Ruby ecosystem already provides similar solutions. As a matter of fact, the generic JS backend wrapper ExecJS is even part of Ruby on Rails core.
Since we have found no project with such stability nor popularity in Python, we decided to write our own.
Basically, we need three things:
- A JS engine;
- A binding between the JS engine and Python;
- The Python interface.
Then you need to interface V8 with Python. In Python, there are two ways to do it. We could either use the Python C API, or ctypes. We have chosen ctypes since it allows a generic and more portable implementation. Indeed, no Python header is needed for compilation. Furthermore, it reduces the number of targets that need maintenance for the binary distribution.
As a reference implementation, we chose the mini_racer gem, written by Sam Saffron. It is a simple one, with everything we needed, that allows to:
- Create isolated contexts;
- Eval code on it that may define functions.
Finally, the Python library. That’s the part that will be shown to the package users. We designed the simplest API possible, that allows to create a context, and either eval or call functions on it.
Check out the Github page of PyMiniRacer.
PyMiniRacer is open source and released under the ISC License.
Installation is straightforward on OSX and most Linux distributions:
$ pip install py_mini_racer
The interface is very straightforward:
Building V8 is a long process. You need a system with a C++ compiler. Then, to download a few gigabytes of V8 source code from Google repository. Eventually, you compile hundreds of C++ files and link them together.
PyMiniRacer does all of that for you :). Thanks to recent efforts in Python binary packaging, we have been able to package PyMiniRacer as Python wheels for the most common platforms and Python versions. You only need to pip install it, and you are ready to go!
If your version is not supported yet, please create a GitHub issue.
We have packaged a 4 MB binary version of PyMiniRacer which installs instantly. These should help you embed V8 into your Python application in a very easy way.
Performance and reliability
- Pass it to V8 after a String::NewFromUtf8 conversion;
- Then V8:
- compiles it with Script::Compile;
- executes it with Script::Run;
- PyMiniRacer converts the result to an abstract binary interface;
- Return it to Python that will convert it using ctypes.
There is virtually no overhead since in step 1. we only copy a string, and in step 4. we perform a very light and low-level conversion from ctypes to Python base objects (strings, numbers, dates, arrays, and dicts).
Regarding reliability, there are very few places where a failure can occur, since most of the work is performed by V8.
About the author
Jean-Baptiste Aviat spent half a decade hunting vulnerabilities at Apple, helping developers solve them, and developing security software. He is now CTO at Sqreen.