Library / SDK
libraries/pywasm avatar
libraries/pywasm

Pywasm runs WebAssembly modules in a pure Python interpreter

A WebAssembly interpreter written in pure Python

518 stars45 forksWebAssemblyMIT

At a glance

What is it?
Pywasm is a WebAssembly interpreter written in pure Python with no third-party libraries, implementing the WebAssembly 2.0 draft specification and WASI Preview 1, with an example suite that covers hashing, recursion, SIMD and WASI programs.
Who is it for?
Pywasm fits a Python developer who needs to run or inspect a WebAssembly module without leaving Python, such as a tool that sandboxes a plugin, a teaching project, or a test harness that needs a readable interpreter, and the no-dependency property means it installs anywhere Python runs.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly WebAssembly, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An interpreter with no dependencies behind it

Pywasm is a WebAssembly interpreter written in pure Python, and the README is emphatic that no third-party libraries are used. That single constraint shapes everything about the project.

It means the package installs anywhere Python runs, with no compilation step and no platform-specific wheels, and it means the interpreter is readable. Someone who wants to understand what a WebAssembly module actually does can read the Python that executes it, which is the opposite of what a compiled runtime gives you.

The spec versions are stated precisely. The wasm version currently in use is the WebAssembly Specification, Release 2.0, Draft 2025-04-25, and the wasi version is WASI Preview 1. The 2.0 draft rather than the finalised 2.0 release is worth noticing, since a module built against a newer feature of the standard may not run.

There is also a hard version floor on the host: Python 3.12 or newer is required. The project is packaged with hatchling, the module is called pywasm, and the homepage given is the GitHub repository.

The primary language of the repository is recorded as WebAssembly, which is a reflection of what the project implements rather than what it is written in.

Instantiating a module and calling a function

The usage is short. You need a wasm module first, and the example file to grab is example/fibonacci/bin/fibonacci.wasm, which you save a copy of in a directory on your machine. Then you instantiate a module directly from its underlying source with the instance_from_file method on a runtime:

python
import pywasm
pywasm.log.lvl = 1

runtime = pywasm.core.Runtime()
m = runtime.instance_from_file('example/fibonacci/bin/fibonacci.wasm')
r = runtime.invocate(m, 'fibonacci', [10])
print(f'fibonacci(10) = {r[0]}')

The shape of the API is worth noting because it is not the usual one. There is no global module registry and no import magic. You create a Runtime object, you ask it for an instance from a file, and you call functions with runtime.invocate, passing the instance, the function name and a list of arguments. The return value is a list, and the example reads the first element.

The log level is set at the top, pywasm.log.lvl = 1, which is the interpreter's own tracing. Being able to turn that on is the kind of thing that matters more than it sounds, since a readable trace of a module's execution is the main practical advantage of an interpreter over a compiled runtime.

The example suite, and what it exercises

The examples are described in a table, and reading it is the fastest way to see what the implementation covers.

The hashing family is the deepest. example/blake2b.py implements the Blake2b hashing algorithm, blake2b_direct.py makes the hash result returned as a value rather than as an output parameter, which is the difference between the two calling conventions in the WebAssembly interface, and blake2b_iter.py is a benchmarking example using the same hash function. blake2b_simd.py uses SIMD instructions to accelerate the hash, which is a meaningful test since SIMD is one of the parts of the specification an interpreter can most easily get wrong.

The rest covers the language and the system interface. example/fibonacci.py contains loop and recursion, fibonacci_env.py calls a Python or native function from wasm, which is the embedding direction that makes an interpreter useful inside a host application. example/pi.py calculates pi using the agm algorithm, so floating point and transcendental functions are exercised.

The WASI examples are the system-facing ones. wasi_httpbin.py executes a wasi program and does an http get from httpbin.org, wasi_ll.py lists information about a directory, wasi_stdout.py captures stdout, and wasi_zen.py prints the poem The Zen of Python. Between them they show the file, network and standard output parts of WASI Preview 1 working.

Running the test suites, and the tools they download

The test story is the part that shows how seriously the specification is taken, because the tests are not the project's own. There are three preparation scripts that download external files first:

bash
$ python script/build_wabt.py # Download wabt tools at res/wabt.
$ python script/build_spec.py # Download spec tests at res/spec.
$ python script/build_wasi.py # Download wasi tests at res/wasi-testsuite.

wabt is the WebAssembly binary toolkit, so the reference toolchain is used to produce the test files, and the official specification test suite and the WASI test suite are fetched from their upstream projects. Running the tests is then a matter of four scripts:

bash
$ python test/example.py      # Test example.
$ python test/main.py         # Test main.
$ python test/spec.py         # Test spec.
$ python test/wasi.py         # Test wasi.

The separation into four suites matches the four layers of the project, the examples, the interpreter core, the specification conformance and the WASI conformance. Downloading the upstream suites rather than vendoring a copy means the tests are the current ones, and it also means the test run needs network access the first time.

Performance, and why PyPy changes the picture

The performance section is unusually candid, and it is worth quoting in shape rather than repeating.

Pywasm is an interpreter implemented using pure Python and its standard library, capable of running on any Python platform. Due to the inherent characteristics of Python, the README says you should not have overly high expectations for pywasm's performance. That is the honest position for an interpreter, and any evaluation that ignores it wastes time.

The second half is more interesting. Pywasm's design makes it jit-friendly, and compared to CPython, its performance on PyPy can improve by approximately 10 times, significantly surpassing the average 3-fold improvement. So the interpreter runs roughly three times faster under PyPy than CPython would suggest, and the design takes it to about ten times.

What that means practically is that the choice of host interpreter is a performance decision, not just a deployment detail. A workload that is too slow on CPython may be usable on PyPy, and a workload that is fine either way does not need PyPy at all.

The README also credits three projects it was inspired by or drew on, wagon, warpy and zstdpy, which is a useful pointer for anyone reading the implementation.

Where Pywasm is the wrong choice

The first limit is throughput, and it is the one the project itself leads with. An interpreter written in Python is orders of magnitude away from a compiled runtime, and the examples in the repository are hash functions and small algorithms, which are the kind of workload where an interpreter can still finish.

The second is the spec version. The wasm version in use is the 2.0 draft dated 2025-04-25, and a module built with a newer feature, or with a proposal that has been merged since, may not run at all.

The third is the WASI scope. The system interface is WASI Preview 1, which is a deliberately small surface: files, sockets, standard streams and the clock. A module expecting a richer host interface, or expecting a specific runtime's extension, is not going to get it here.

The fourth is that the architecture is not WebAssembly's. WASI Preview 1 has a process model with one linear memory and a set of capabilities, and an interpreter that executes the instructions in Python is not going to give you the same isolation guarantees as a runtime that maps memory and traps out of bounds, because a Python-level bug in the interpreter is a Python-level bug in your process. That is fine for a tool and a test harness, and it is a reason to think twice for anything exposed to untrusted modules.

The fifth is the project scale. A single author, a version at 2.2.3, and a recent push, describe something maintained and moving but small, and the test suites depend on downloading upstream files, so a CI setup has to account for that.

Licence, packaging and the state of the project

The licence is MIT, and the package metadata points at a LICENSE file in the repository. The build backend is hatchling, and the project metadata names the author as Mohanson.

The release history is v2.2.3 from 2026-05-13, v2.2.2 from 2026-01-27 and v2.2.1 from 2025-09-25, and the last push to the repository was on 2026-10-19 with the repository not archived. A 2.x line with regular releases over about a year suggests a project that has settled into a maintenance rhythm after finding its shape.

The repository layout is organised around the layers. There is the pywasm package directory, the example directory with one subdirectory per example, a res directory for resources including the downloaded wabt, spec and wasi files, a script directory holding the build scripts, and a test directory with the four test suites. There is also a MANIFEST.in for the packaging and a .github directory for the workflows.

There is no separate documentation site in the README, which is worth noting for a project of this size. The specification versions, the example table and the test scripts are the documentation, and the examples are the tutorial.

Editorial conclusion

Pywasm fits a Python developer who needs to run or inspect a WebAssembly module without leaving Python, such as a tool that sandboxes a plugin, a teaching project, or a test harness that needs a readable interpreter, and the no-dependency property means it installs anywhere Python runs. It is the wrong tool if you need throughput, since the README says not to have overly high expectations for performance, and it is the wrong tool if you want a WebAssembly runtime for a production server. Before you adopt it, check three things: that your Python is 3.12 or newer, that you understand the performance ceiling of an interpreter, and that the module you need actually uses a feature this implementation covers, since the spec version is the 2.0 draft rather than the final release. The code is MIT licensed, the current version is 2.2.3 from 2026-05-13, and the last push was on 2026-10-19.

Frequently asked questions

What is Pywasm and what does it implement?

Pywasm is a WebAssembly interpreter written in pure Python with no third-party libraries. It implements the WebAssembly Specification, Release 2.0 draft dated 2025-04-25, and WASI Preview 1.

How do I run a WebAssembly module with Pywasm?

Create a runtime, instantiate the module from a file with runtime.instance_from_file, and call a function with runtime.invocate, passing the instance, the function name and a list of arguments. The README's example does that with the fibonacci module and prints the first element of the returned list.

What Python version does Pywasm need?

Python 3.12 or newer is required, according to the README. The package installs with `pip install pywasm` and has no third-party dependencies.

How does Pywasm test itself against the WebAssembly specification?

It downloads the external test files first, with script/build_wabt.py, script/build_spec.py and script/build_wasi.py, then runs test/example.py, test/main.py, test/spec.py and test/wasi.py.

Is Pywasm fast enough for production use?

The README says not to have overly high expectations for performance, since it is an interpreter written in Python. It adds that the design is jit-friendly, so on PyPy performance can improve by about 10 times over CPython, against an average 3-fold improvement.

Official sources

  1. Issues
  2. libraries/pywasm on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/libraries-pywasm.svg)](https://hysenlabs.com/projects/libraries-pywasm)

Was this useful?