🐍🕸 WebAssembly runtime for Python
Full Changelog: https://github.com/wasmerio/wasmer-python/compare/1.1.0...1.1.1
Python Packages:
Python Packages:
Python Packages:
The whole API changed to better match Wasmer and Wasm C API
from wasmer import engine, wat2wasm, ImportObject, Module, Store, Instance
from wasmer_compiler_cranelift import Compiler
# Create an Engine
jit = engine.JIT(Compiler)
# Create a store.
store = Store(jit)
# Let's compile the Wasm module.
module = Module(store, wasm_bytes)
# Create an empty import object.
import_object = ImportObject()
# Let's instantiate the Wasm module.
instance = Instance(module, import_object)
Please refer to the examples and documentation to learn more about the changes.
New Buffer
class to read memory fast (#125 by @Hywan)
To get the memory buffer, use the Memory.buffer
getter. A Buffer
implements the Python Buffer Protocol. The goal is to get faster reading operations than the existing memory views API.
bytearray(instance.memory.buffer)
is 15x faster than instance.memory.int8_view()
.
memoryview(instance.memory.buffer)
is 14x faster than instance.memory.int8_view()
.
# Get the memory buffer.
buffer = Instance(wasm_bytes).memory.buffer
# Use the buffer with `memoryview`
memory_view = memoryview(buffer)
# Use the buffer with `byte_array`
byte_array = bytearray(buffer)
# Enjoy the byte array API!
assert byte_array[3:9].decode() == 'Wasmer'
Support exported globals through the Instance.globals
API (#120 by @Hywan)
instance = Instance(wasm_bytes)
x = instance.globals.x
assert x.value == 7
assert x.mutable == True
x.value = 153
assert x.value == 153
Implement a WebAssembly custom section query API (#118 by @Hywan)
Module.custom_section_names
is used to list all the custom section names.
Module.custom_section
is used to read the value of a specific custom section. If the custom section does not exist, None
is returned.
assert Module(wasm_bytes).custom_section('hello') == b'World!'
Add the Module.imports
getter to list all imports, and introduce the ImportKind
enum (#117 by @Hywan)
assert Module(wasm_bytes).imports == [
{
'kind': ImportKind.FUNCTION,
'namespace': 'ns',
'name': 'f1',
},
{
'kind': ImportKind.FUNCTION,
'namespace': 'ns',
'name': 'f2',
},
{
'kind': ImportKind.MEMORY,
'namespace': 'ns',
'name': 'm1',
# Additional pairs specific to `MEMORY`
'minimum_pages': 3,
'maximum_pages': 4,
},
{
'kind': ImportKind.GLOBAL,
'namespace': 'ns',
'name': 'g1',
# Additional pairs specific to `GLOBAL`
'mutable': False,
'type': 'f32'
},
{
'kind': ImportKind.TABLE,
'namespace': 'ns',
'name': 't1',
# Additional pairs specific to `TABLE`
'minimum_elements': 1,
'maximum_elements': 2,
'element_type': 'anyfunc',
}
]
Add the Module.exports
getter to list all exports, and introduce the ExportKind
enum (#115 and #116 by @Hywan)
assert Module(wasm_bytes).exports == [
{
'name': 'memory',
'kind': ExportKind.MEMORY,
},
{
'name': '__heap_base',
'kind': ExportKind.GLOBAL,
},
{
'name': '__data_end',
'kind': ExportKind.GLOBAL,
},
{
'name': 'sum',
'kind': ExportKind.FUNCTION,
},
]
Support modules without an exported memory (#114 by @Hywan)
instance = Instance(wasm_bytes)
# Now the `memory` getter can return `None`
assert instance.memory == None
Add Rust trait to allow inspection of exported functions (#71 by @Mec-iS)
instance = Instance(wasm_bytes)
assert isinstance(instance.exports.sum.getfullargspec, str)
assert isinstance(instance.exports.sum.getargs, str)
Memory views support slice assignment (#63 by @Hywan).
memory = instance.memory.uint8_view()
memory[0:4] = b"abcd"
The slice is bound to the memory view length. The slice accepts start, stop, and step parameters, so it is possible to write view[0:5:2]
for instance. There is a huge difference with list slice assignment in Python: Elements in memory cannot be moved, so the assignment only overwrite elements.
// With regular Python list
a = [1, 2, 3, 4, 5]
a[1:3] = [10, 11, 12]
assert a == [1, 10, 11, 12, 4, 5]
// With WebAssembly memory views
view[0:5] = [1, 2, 3, 4, 5]
view[1:3] = [10, 11, 12]
assert view[0:5] == [1, 10, 11, 4, 5]
It is 10 times faster than a regular loop to write data in memory.
Read the pull request to learn more.
Make wasmer silently available anywhere with wasmer-any
(#62 by @syrusakbary)
Memory
(#127 by @Hywan)spin
from 0.5.0 to 0.5.2 (#72]#56 Add the Memory.grow
method (@Hywan)
#54 Bound slice to the size of the memory view —allow to write memory_view[0:]
with no error— (@Hywan)
#51 Add wasmer.__core_version__
to get the runtime [Wasmer] version (@Hywan)
#48 Support module serialization with Module.serialize
and Module.deserialize
(@Hywan)
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)
#47 Introduce the Module
class, with Module.validate
and Module.instantiate
(@Hywan)
from wasmer import Module
# Get the Wasm bytes.
wasm_bytes = open('my_program.wasm', 'rb').read()
# Compile the Wasm 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
#27 Add wasmer.__version__
to get the extension version (@Mec-iS)
greet
example (@Hywan)just rust
to just build
(@Hywan)