Skip to main content

Wasmer logo   Join the Wasmer Community Pypi License

Wasmer is a Python library for executing WebAssembly binaries:

  • Easy to use: The wasmer API mimics the standard WebAssembly API,
  • Fast: wasmer executes the WebAssembly modules at native speed,
  • Safe: All calls to WebAssembly will be fast, but more importantly, completely safe and sandboxed.

Install

To install the wasmer Python library, just run this command in your shell:

$ pip install wasmer

Note: There is a limited set of wheels published so far. More are coming.

View the wasmer on Pypi.

Example

There is a toy program in examples/simple.rs, written in Rust (or any other language that compiles to WebAssembly):

#[no_mangle]
pub extern fn sum(x: i32, y: i32) -> i32 {
    x + y
}

After compilation to WebAssembly, the examples/simple.wasm binary file is generated. (Download it).

Then, we can excecute it in Python:

from wasmer import Instance

wasm_bytes = open('simple.wasm', 'rb').read()
instance = Instance(wasm_bytes)
result = instance.exports.sum(5, 37)

print(result) # 42!

And then, finally, enjoy by running:

$ python examples/simple.py

API of the wasm extension/module

The Instance class

Instantiates a WebAssembly module represented by bytes, and calls exported functions on it:

from wasmer import Instance

# Get the Wasm module as bytes.
wasm_bytes = open('my_program.wasm', 'rb').read()

# Instantiates the Wasm module.
instance = Instance(wasm_bytes)

# Call a function on it.
result = instance.exports.sum(1, 2)

print(result) # 3

All exported functions are accessible on the exports getter. Arguments of these functions are automatically casted to WebAssembly values. If one wants to explicitely pass a value of a particular type, it is possible to use the Value class, e.g. instance.exports.sum(Value.i32(1), Value.i32(2)). Note that for most usecases, this is not necessary.

The memory getter exposes the Memory class representing the memory of that particular instance, e.g.:

view = instance.memory.uint8_view()

See below for more information.

The Value class

Builds WebAssembly values with the correct types:

from wasmer import Value

# Integer on 32-bits.
value_i32 = Value.i32(7)

# Integer on 64-bits.
value_i64 = Value.i64(7)

# Float on 32-bits.
value_f32 = Value.f32(7.42)

# Float on 64-bits.
value_f64 = Value.f64(7.42)

The Value.[if](32|64) static methods must be considered as static constructors.

The __repr__ method allows to get a string representation of a Value instance:

print(repr(value_i32)) # I32(7)

The Memory class

A WebAssembly instance has its own memory, represented by the Memory class. It is accessible by the Instance.memory getter.

The Memory class offers methods to create views of the memory internal buffer, e.g. uint8_view, int8_view, uint16_view etc. All these methods accept one argument: offset, to subset the memory buffer at a particular offset. These methods return respectively a *Array object, i.e. uint8_view returns a Uint8Array object etc.

offset = 7
view = instance.memory.uint8_view(offset)

print(view[0])

The *Array classes

These classes represent views over a memory buffer of an instance.

Class View buffer as a sequence of… Bytes per element
Int8Array int8 1
Uint8Array uint8 1
Int16Array int16 2
Uint16Array uint16 2
Int32Array int32 4
Uint32Array uint32 4

All these classes share the same implementation. Taking the example of Uint8Array, the class looks like this:

class Uint8Array:
    @property
    def bytes_per_element()

    def __len__()
    def __getitem__(index|slice)
    def __setitem__(index, value)

Let's see it in action:

from wasmer import Instance

# Get the Wasm module as bytes.
wasm_bytes = open('my_program.wasm', 'rb').read()

# Instantiates the Wasm module.
instance = Instance(wasm_bytes)

# Call a function that returns a pointer to a string for instance.
pointer = instance.exports.return_string()

# Get the memory view, with the offset set to `pointer` (default is 0).
memory = instance.memory.uint8_view(pointer)

# Read the string pointed by the pointer.
nth = 0;
string = ''

while True:
    char = memory[nth]
    
    if char == 0:
        break

    string += chr(char)
    nth += 1

print(string) # Hello, World!

A slice can be used as index of the __getitem__ method, which is useful when we already know the size of the data we want to read, e.g.:

print(''.join(map(chr, memory[0:13]))) # Hello, World!

Notice that *Array treat bytes in little-endian, as required by the WebAssembly specification, Chapter Structure, Section Instructions, Sub-Section Memory Instructions:

All values are read and written in little endian byte order.

Each view shares the same memory buffer internally. Let's have some fun:

int8 = instance.memory.int8_view()
int16 = instance.memory.int16_view()
int32 = instance.memory.int32_view()

               b
            ┌┬┬┬┬┬┬┐
int8[0] = 0b00000001
               b
            ┌┬┬┬┬┬┬┐
int8[1] = 0b00000100
               b
            ┌┬┬┬┬┬┬┐
int8[2] = 0b00010000
               b
            ┌┬┬┬┬┬┬┐
int8[3] = 0b01000000

// No surprise with the following assertions.
                       b
                    ┌┬┬┬┬┬┬┐
assert int8[0] == 0b00000001
                       b
                    ┌┬┬┬┬┬┬┐
assert int8[1] == 0b00000100
                       b
                    ┌┬┬┬┬┬┬┐
assert int8[2] == 0b00010000
                       b
                    ┌┬┬┬┬┬┬┐
assert int8[3] == 0b01000000

// The `int16` view reads 2 bytes.
                        b       b
                     ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert int16[0] == 0b00000100_00000001
                        b       b
                     ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert int16[1] == 0b01000000_00010000

// The `int32` view reads 4 bytes.
                        b       b       b       b
                     ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐ ┌┬┬┬┬┬┬┐
assert int32[0] == 0b01000000_00010000_00000100_00000001;

The validate function

Checks whether the given bytes represent valid WebAssembly bytes:

from wasmer import validate

wasm_bytes = open('my_program.wasm', 'rb').read()

if not validate(wasm_bytes):
    print('The program seems corrupted.')

This function returns a boolean.

Development

The Python extension is written in Rust, with rust-cpython and pyo3-pack.

To set up your environment, run only once:

$ just prelude

It will install pyo3-pack for Python and for Rust. It will also install virtualenv.

Then, simply run:

$ .env/bin/activate
$ just rust
$ just python-run examples/simple.py

If you need to interact with Python, or run a specific file, use the following commands:

$ just python-run
$ just python-run file/to/run.py

Finally, to inspect the extension; run:

$ just inspect

(Yes, you need just).

Testing

Once the extension is compiled and installed (just run just rust), run the following command:

$ just test

What is WebAssembly?

Quoting the WebAssembly site:

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

About speed:

WebAssembly aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms.

About safety:

WebAssembly describes a memory-safe, sandboxed execution environment […].

License

The entire project is under the BSD-3-Clause license. Please read the LICENSE file.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

wasmer-0.1.5-cp37-cp37m-manylinux1_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.7m

wasmer-0.1.5-cp37-cp37m-macosx_10_7_x86_64.whl (972.5 kB view details)

Uploaded CPython 3.7mmacOS 10.7+ x86-64

wasmer-0.1.5-cp36-cp36m-manylinux1_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.6m

wasmer-0.1.5-cp36-cp36m-macosx_10_7_x86_64.whl (972.4 kB view details)

Uploaded CPython 3.6mmacOS 10.7+ x86-64

wasmer-0.1.5-cp35-cp35m-manylinux1_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.5m

wasmer-0.1.5-cp35-cp35m-macosx_10_7_x86_64.whl (972.3 kB view details)

Uploaded CPython 3.5mmacOS 10.7+ x86-64

File details

Details for the file wasmer-0.1.5-cp37-cp37m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp37-cp37m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 fccc16a57700df02df68f0cffd5269f2deea26f391fe06c6f9dec379c53fa81c
MD5 dd801c1a6b367a3707bf08b3847f1c4d
BLAKE2b-256 743397bad814ab994d4dc1913abd8f301143da7f702b531cde889b36a6e0e165

See more details on using hashes here.

File details

Details for the file wasmer-0.1.5-cp37-cp37m-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp37-cp37m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 fe613759adbc590c78296eaec2041f57b2ef7e699e4fc66d5b1ee4c86958d039
MD5 adf57a612b35247fd927df9fe7748941
BLAKE2b-256 6fb6580feafc36d40d07e3983ff800afec2a002284f0c77707ec68ab8e2a5e92

See more details on using hashes here.

File details

Details for the file wasmer-0.1.5-cp36-cp36m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 6cbcf5a7867565f9d06decb8e3ab392dafec7a431b93d900e36f926daddd6aed
MD5 04c32299dba2694c30dc12b09050ccbc
BLAKE2b-256 8c9a82c4f3856361311da08cac9b04058e7a110493aeeac1ccbd4900a25eb1fd

See more details on using hashes here.

File details

Details for the file wasmer-0.1.5-cp36-cp36m-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp36-cp36m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 48059fb6dae38f7ef2050c77d6aa3849280434fdbe8aadc94a873675884fd382
MD5 ede9b655fce897c4e26e2a84c752f788
BLAKE2b-256 c09719a0d91c73ec5126c0f5aa6eefc114d59c7320fc271f2255227c6e9db811

See more details on using hashes here.

File details

Details for the file wasmer-0.1.5-cp35-cp35m-manylinux1_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp35-cp35m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 98983c69e99d9f2dabe9637c5132613c222f5a5940f0c31dc018c9381a7ea91d
MD5 3901b84b30426cc9b827ad10b2a2c8ac
BLAKE2b-256 ec7128f411d134800f0e0650184a1cceeabd817174d3a8c5dcac60366ab19589

See more details on using hashes here.

File details

Details for the file wasmer-0.1.5-cp35-cp35m-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for wasmer-0.1.5-cp35-cp35m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 b3604a6f1d9952bf93e4b0e46ec0f4afaad53f1c839ce15804b4d0c86a988b44
MD5 9bca17469b2de12ec64618789a33709c
BLAKE2b-256 ef48ad60aef0443ec9e207359a33f42e7edf48cec899d7a33aff03988242a53c

See more details on using hashes here.

Release history Release notifications | RSS feed

1.1.0

14 files

1.0.0

14 files

1.0.0a2

2 files

1.0.0a1

3 files

0.4.1

7 files

0.3.0

7 files

0.2.0

6 files

This release

0.1.5 This release

6 files

0.1.4

6 files

0.1.3

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page