Skip to main content

Wasmer logo

Join the Wasmer Community Pypi Number of downloads on 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 as fast as possible, close to 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 wasmer 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()

# Instantiate 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 Module class

Compiles a sequence of bytes into a WebAssembly module. From here, it is possible to instantiate it:

from wasmer import Module

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

# Compile the bytes into a Wasm module.
module = Module(wasm_bytes)

# Instantiate the Wasm module.
instance = module.instantiate()

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

print(result) # 3

The Module.serialize method and its complementary Module.deserialize static method help to respectively serialize and deserialize a compiled WebAssembly module, thus saving the compilation time for the next use:

from wasmer import Module

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

# Compile the bytes into a Wasm module.
module1 = Module(wasm_bytes)

# Serialize the module.
serialized_module = module1.serialize()

# Let's forget about the module for this example.
del module1

# Deserialize the module.
module2 = Module.deserialize(serialized_module)

# Instantiate and use it.
result = module2.instantiate().exports.sum(1, 2)

print(result) # 3

A serialized module is a sequence of bytes. They can be saved in any storage.

The Module.validate static method check whether the given bytes represent valid WebAssembly bytes:

from wasmer import Module

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

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

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.grow method allows to grow the memory by a number of pages (of 65kb each).

instance.memory.grow(1)

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()

# Instantiate 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)
memory_length = len(memory)

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

while nth < memory_length:
    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

Development

The Python extension is written in Rust, with pyo3 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 build
$ 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 build), 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 MIT 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.3.0-py3-none-any.whl (1.3 kB view details)

Uploaded Python 3

wasmer-0.3.0-cp37-cp37m-manylinux1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.7m

wasmer-0.3.0-cp37-cp37m-macosx_10_7_x86_64.whl (994.0 kB view details)

Uploaded CPython 3.7mmacOS 10.7+ x86-64

wasmer-0.3.0-cp36-cp36m-manylinux1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.6m

wasmer-0.3.0-cp36-cp36m-macosx_10_7_x86_64.whl (994.3 kB view details)

Uploaded CPython 3.6mmacOS 10.7+ x86-64

wasmer-0.3.0-cp35-cp35m-manylinux1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.5m

wasmer-0.3.0-cp35-cp35m-macosx_10_7_x86_64.whl (994.2 kB view details)

Uploaded CPython 3.5mmacOS 10.7+ x86-64

File details

Details for the file wasmer-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: wasmer-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 1.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.3

File hashes

Hashes for wasmer-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1d2c337425721fd9ac6c6b17698ef8a9795b236a38b0e3c85872a5845ffb0d90
MD5 1b86acbbd4ce1f9fc58cbb428e66f83b
BLAKE2b-256 c89103f6a73ebce72f0bc208314403d74bf6b11082f689e9693a3dfafd75b105

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp37-cp37m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 fcfe2c7a9fbf323f3520ef9766b82e80cd433d7f8c87ff084b18bcde716923af
MD5 53f21d0390bccc9aca2299869788b4f6
BLAKE2b-256 ee5f93eac0a1c307ab97df5fd91cbb91c23dc464df604f1af62b520031abd8d7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp37-cp37m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 2edb87608daa3b46bd2520e0b5b90580fde9c805be4d92eeb98c22b29a21abc6
MD5 21c38368d7668f073f1f1303c5823194
BLAKE2b-256 02618cd89aec2149cf81c005532157471bb1e0c4837a2b9332e619454ec99ded

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 e547b1074e52c10f0581de415b509aa61e577f5248340a68b356938393d773c8
MD5 83013f26426f0025aac1039de011149c
BLAKE2b-256 a789739e34035f355ab4aa0801f5cdda07ce50247d7feed38a6075b8962514ed

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp36-cp36m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 4fe592b764fc09d535757682d0ced6da1037976a7eb97986fce3523779a89682
MD5 b8a874746e9534928860f09c28ba4844
BLAKE2b-256 f3d143eedf0c73e9b8af15f7382ee9dbdfac043f2424187d716f8563808346f1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp35-cp35m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 7b5235dd4ee1cf48d054e7216a1fefe15b8b1a48ffe5e9bb2655724cf84d7a31
MD5 f25c78c02d68e2707b488eb1dc054e83
BLAKE2b-256 7a8192e72fa0643a8360edf12eadaf76bc63592187e5190de2c75be807056ce2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wasmer-0.3.0-cp35-cp35m-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 75d854cb5acdc32f289ceb310a72d66190fa531dd126eac970ed6788939a5d40
MD5 a674346ea871cf33cc9622dd22fb7c37
BLAKE2b-256 ef62c345db886f6ec90f1d9e3398ea2ed18432223a564eb040bc5e4468746687

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

This release

0.3.0 This release

7 files

0.2.0

6 files

0.1.5

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