Python in WebAssembly
Python is one of the most popular programming languages in the world, and its WebAssembly implementation seems to be coming along quickly. While it is not yet ready for use, we anticipate it will be functional in the first half of 2022.
The most momentum seems to be in the CPython community, which is rapidly approaching both Emscripten-based and WASI-based implementations.
Available Implementations
When things land, they will be in the GitHub CPython repo. The expected milestone is CPython 3.11.
More recently, we have been using SingleStore’s wasi-python project. As the name implies, it has full WASI support for filesystem, environment variables, random numbers, and clock access (and possibly others).
Usage
Using Python, a scripting language, is a little different than using compiled languages like Rust or AssemblyScript. Not only will the runtime need the Python interpreter compiled to Wasm, but it will also need a number of Python libraries available on the WASI filesystem. We pre-built a version that you can use.
Python scripts that are used this way do not need to be compiled to WebAssembly. They simply need to be loaded into the python3.wasm
at startup time.
Example
This section provides a basic example of running a Python 3 script. It is derived from a Fermyon.com Python tutorial.
All of our examples follow a documented pattern using common tools.
Because we need both the Python 3 interpreter (compiled to Wasm) and the core Python 3 libraries, the first step in this example is to clone our pre-built demo repo: https://github.com/fermyon/wagi-python.
If you would prefer, you can build from source from either the SingleStore Python repository or from the CPython repository.
A simple Python script for Wagi looks like this:
import sys
print('Content-Type: text/plain; charset=UTF-8')
print()
print('Hello, World')
We’ll put the script above in code/hello.py
.
When creating a modules.toml
for Wagi, you will need to use the argv
directive to tell Wagi how to invoke python3.wasm
:
[[module]]
route = "/"
module = "opt/wasi-python/bin/python3.wasm"
volumes = { "/code" = "code", "/opt" = "opt" }
argv = "python /code/hello.py"
Note that the argv
line looks like the command you would normally invoke. However, it is not executed in a shell. Instead, this is provided so that the Python interpreter itself can see how it should act.
To run the example, start wagi
:
$ wagi -c modules.toml
No log_dir specified, using temporary directory /var/folders/rk/mkbs8vx12zs0gkm680h_gth00000gn/T/.tmpTxamNm for logs
Ready: serving on http://127.0.0.1:3000
(Note that the above may take several seconds.)
At this point you can use a web browser or curl to check the results:
$ curl localhost:3000
Hello, World
Learn More
Here are some great resources:
- A detailed document about the current state and features of Wasm in the latest CPython version
- Fermyon.com published a slightly more in-depth Python and Wasm tutorial
- An in-browser Python shell in Wasm
- One version of CPython + Wasm, where they are working on WASI support
- Recent work on WASI support in Python
- CPython has made progress on an Emscripten-targeted Wasm target. See also this patch.
- There is currently a patch for Python 3.11.
- Much is happening on the WebAssembly Discord server. Check the
#python
channel.