Home
Minimal, modern embedded V8 for Python.
Features¶
- Latest ECMAScript support
- Web Assembly support
- Unicode support
- Thread safe
- Re-usable contexts
MiniRacer can be easily used by Django or Flask projects to minify assets, run babel or WASM modules.
New home! (As of March 2024)¶
PyMiniRacer was created by Sqreen, and originally lived at
https://github.com/sqreen/PyMiniRacer with the PyPI package
py-mini-racer
.
As of March 2024, after a few years without updates, I have
reached out to the original Sqreen team. We agreed that I should fork PyMiniRacer,
giving it a new home at https://github.com/bpcreech/PyMiniRacer with a new PyPI
package mini-racer
(note: no py-
). It now
has a new version for the
first time since 2021!
Examples¶
MiniRacer is straightforward to use:
and then:
$ python3
>>> from py_mini_racer import MiniRacer
>>> ctx = MiniRacer()
>>> ctx.eval("1+1")
2
>>> ctx.eval("var x = {company: 'Sqreen'}; x.company")
'Sqreen'
>>> print(ctx.eval("'❤'"))
❤
>>> ctx.eval("var fun = () => ({ foo: 1 });")
Variables are kept inside of a context:
You can evaluate whole scripts within JavaScript, or define and return JavaScript function objects and call them from Python (new in v0.11.0):
JavaScript Objects and Arrays are modeled in Python as dictionaries and lists (or, more
precisely,
MutableMapping
and
MutableSequence
instances), respectively (new in v0.11.0):
>>> obj = ctx.eval("var obj = {'foo': 'bar'}; obj")
>>> obj["foo"]
'bar'
>>> list(obj.keys())
['foo']
>>> arr = ctx.eval("var arr = ['a', 'b']; arr")
>>> arr[1]
'b'
>>> 'a' in arr
True
>>> arr.append(obj)
>>> ctx.eval("JSON.stringify(arr)")
'["a","b",{"foo":"bar"}]'
Meanwhile, call
uses JSON to transfer data between JavaScript and Python, and converts
data in bulk:
Composite values are serialized using JSON. Use a custom JSON encoder when sending non-JSON encodable parameters:
import json
from datetime import datetime
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return json.JSONEncoder.default(self, obj)
>>> ctx.eval("var f = function(args) { return args; }")
>>> ctx.call("f", datetime.now(), encoder=CustomEncoder)
'2017-03-31T16:51:02.474118'
MiniRacer is ES6 capable:
MiniRacer supports asynchronous execution using JS Promise
instances (new in
v0.10.0):
>>> promise = ctx.eval(
... "new Promise((res, rej) => setTimeout(() => res(42), 10000))")
>>> promise.get() # blocks for 10 seconds, and then:
42
You can use JS Promise
instances with Python async
(new in v0.10.0):
>>> import asyncio
>>> async def demo():
... promise = ctx.eval(
... "new Promise((res, rej) => setTimeout(() => res(42), 10000))")
... return await promise
...
>>> asyncio.run(demo()) # blocks for 10 seconds, and then:
42
JavaScript null
and undefined
are modeled in Python as None
and JSUndefined
,
respectively:
You can install callbacks from JavaScript to Python (new in v0.12.0):
>>> async def read_file(fn):
... with open(fn) as f: # (or aiofiles would be even better here)
... return f.read()
...
>>> async def get_dictionary():
... async with ctx.wrap_py_function(read_file) as jsfunc:
... # "Install" our JS function on the global "this" object:
... ctx.eval('this')['read_file'] = jsfunc
... d = await ctx.eval('this.read_file("/usr/share/dict/words")')
... return d.split()
...
>>> dictionary = asyncio.run(get_dictionary())
>>> print(dictionary[0:10])
['A', 'AA', 'AAA', "AA's", 'AB', 'ABC', "ABC's", 'ABCs', 'ABM', "ABM's"]
Note that adding Python callbacks may degrade the security properties of PyMiniRacer! See PyMiniRacer's security goals.
MiniRacer supports the ECMA Intl
API:
# Indonesian dates!
>>> ctx.eval('Intl.DateTimeFormat(["ban", "id"]).format(new Date())')
'16/3/2024'
V8 heap information can be retrieved:
>>> ctx.heap_stats()
{'total_physical_size': 1613896,
'used_heap_size': 1512520,
'total_heap_size': 3997696,
'total_heap_size_executable': 3145728,
'heap_size_limit': 1501560832}
A WASM example is available in the
tests
.
Compatibility¶
PyMiniRacer is compatible with Python 3.8-3.12 and is based on ctypes
.
PyMiniRacer is distributed using wheels on PyPI. The wheels are intended to provide compatibility with:
OS | x86_64 | aarch64 |
---|---|---|
macOS ≥ 10.9 | ✓ | ✓ |
Windows ≥ 10 | ✓ | ✖ |
Ubuntu ≥ 20.04 | ✓ | ✓ |
Debian ≥ 11 | ✓ | ✓ |
RHEL ≥ 9 | ✓ | ✓ |
other Linuxes with glibc ≥ 2.31 | ✓ | ✓ |
Alpine ≥ 3.19 | ✓ | ✓ |
other Linux with musl ≥ 1.2 | ✓ | ✓ |
If you have a up-to-date pip and it doesn't use a wheel, you might have an environment for which no wheel is built. Please open an issue.
Developing and releasing PyMiniRacer¶
Credits¶
Built with love by Sqreen.
PyMiniRacer launch was described in
this blog post
.
PyMiniRacer is inspired by mini_racer, built for the Ruby world by Sam Saffron.
In 2024, PyMiniRacer was revived, and adopted by Ben Creech. Upon discussion with the original Sqreen authors, we decided to re-launch PyMiniRacer as a fork under https://github.com/bpcreech/PyMiniRacer and https://pypi.org/project/mini-racer/.