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.

Available Implementations

WebAssembly support is officially available in CPython 3.11 and after. The GitHub CPython repo has all of the code.

There is also a Spin SDK for Python that uses CPython, but reduces startup time by preloading and initializing the scripts. There’s a detailed blog post about Python on Fermyon.com that explains this.

Usage

The Spin SDK makes it very easy to build Python-based Wasm applications simply by using a Spin template that handles all of the heavy lifting.

Spin’s Python HTTP Request Handler Template

Spin’s Python HTTP Request Handler Template can be installed from spin-python-sdk repository using the following command:

$ spin templates install --git https://github.com/fermyon/spin-python-sdk --update

The above command will install the http-py template and produce an output similar to the following:

Copying remote template source
Installing template http-py...
Installed 1 template(s)

+---------------------------------------------+
| Name      Description                       |
+=============================================+
| http-py   HTTP request handler using Python |
+---------------------------------------------+

Please note: For more information about managing spin templates, see the templates section in the Spin Command Line Interface (CLI) documentation.

Example

Let’s use Spin’s Python HTTP request handler template, to create a new project:

$ spin new python-example -t http-py --accept-defaults

System Housekeeping (Use a Virtual Environment)

Once the app is created, we can change into the python-example directory, create and activate a virtual environment and then install the apps requirements:

$ cd python-example

Create a virtual environment directory (we are still inside the Spin app directory):

# python<version> -m venv <virtual-environment-name>
$ python3 -m venv venv-dir

Activate the virtual environment (this command depends on which operating system you are using):

# macOS command to activate
$ source venv-dir/bin/activate

The (venv-dir) will prefix your terminal prompt now:

(venv-dir) user@123-456-7-8 python-example %

Requirements

The requirements.txt, by default, contains the references to the spin-sdk and componentize-py packages. These can be installed right there in your virtual environment using:

$ pip3 install -r requirements.txt

Take a look at the scaffolded program in app.py:

from spin_sdk.http import IncomingHandler, Request, Response

class IncomingHandler(IncomingHandler):
    def handle_request(self, request: Request) -> Response:
        return Response(
            200,
            {"content-type": "text/plain"},
            bytes("Hello from Python!", "utf-8")
        )

Change into the app directory and install the requirements:

$ pip3 install -r requirements.txt

Compile a Wasm binary with the scripts preloaded, and then start up a local server:

$ spin build --up
Building component python-example with `spin py2wasm app -o app.wasm`
Spin-compatible module built successfully
Finished building all Spin components
Logging component stdio to ".spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
  python-example: http://127.0.0.1:3000 (wildcard)

Test it with curl:

$ curl localhost:3000/
Hello from the Python SDK

The file app.wasm contains both the interpreter (in an initialized state) and all of the userland code:

$ ls -lah app.wasm
-rw-r--r--  1 technosophos  staff    24M Oct 26 18:22 app.wasm

Learn More

Live Code Tuesday Video (Python & Wasm - Let’s talk about componentize-py w/ Joel Dice, Streamed live on Mar 13, 2024)

Joel’s video on Spin, Python, and Components (Recorded at WasmCon on Sep 12, 2023):

Here are some great resources:

Troubleshooting

If you bump into issues when installing the requirements.txt. For example:

error: externally-managed-environment
× This environment is externally managed

Please note, this error is specific to Homebrew-installed Python installations and occurs because installing a non-brew-packaged Python package requires you to either:

  • create a virtual environment using python3 -m venv path/to/venv, or
  • use the --break-system-packages option in your pip3 install command i.e. pip3 install -r requirements.txt --break-system-packages

We recommend installing a virtual environment using venv, as shown in the system housekeeping section above.