pyjs is a modern pybind11 + emscripten embind based Python <-> JavaScript foreign function interface (FFI) for wasm/emscripten compiled Python. The API is loosely based on the FFI of pyodide.
- Python 3.14, emscripten 6,
wasm32andwasm64 - runs in the browser main thread and in web workers
- asyncio support:
awaitJavaScript promises from Python and Python coroutines from JavaScript - tested in Chromium, Firefox and WebKit (Safari)
- distributed via emscripten-forge
See the documentation.
- the Python REPL in the docs
- the JupyterLite playground
- to create your own JupyterLite deployments, use xeus-lite-demo
pyjs is installed into an emscripten-forge environment:
# environment.yml
name: my-pyjs-env
channels:
- https://repo.prefix.dev/emscripten-forge/6x
- conda-forge
dependencies:
- pyjs-dev
- numpymicromamba create -f environment.yml --platform emscripten-wasm32 --prefix /path/to/envSee deploying pyjs for how to pack the environment with empack and load it in the browser.
Access JavaScript from Python:
import pyjs
# hello world
pyjs.js.console.log("Hello, World!")
# create a JavaScript function to add two numbers
js_function = pyjs.js.Function("a", "b", """
console.log("Adding", a, "and", b)
return a + b
""")
# call the function
result = js_function(1, 2)Access Python from JavaScript:
// hello world
pyjs.eval("print('Hello, World!')")
// eval a python expression and get the result
const py_list = pyjs.eval("[i for i in range(10)]")
// access
console.log(py_list.get(0)) // same as py_list[0] on the python sideBuilding, testing, benchmarking and building the docs all go through
build_local.sh (only micromamba is needed),
the CI uses the same script:
./build_local.sh wasm32 # build pyjs
./build_local.sh wasm64 --test # build + run the tests in the browser
BROWSERS="chromium firefox webkit" ./build_local.sh wasm32 --test
./build_local.sh wasm32 --bench # FFI / asyncio benchmarks
./build_local.sh wasm32 --docs # sphinx docs + jupyterliteSee development for details.