wasmer-python
wasmer-python copied to clipboard
Capturing output from WASI binary (produced by TinyGo 0.26.0)
Summary
I want to use a WASI binary produced by TinyGo (0.26.0) in Python capturing the output from an exported function to a variable.
Specifically the parse
method defined here:
https://github.com/sfomuseum/go-edtf/blob/wasi/cmd/parse-wasi/main.go
Which I can build and test like this:
$> tinygo build -o parse.wasm -target wasi ./cmd/parse-wasi/main.go
$> wasmer parse.wasm 2022-01-01
2022-01-01
If I run the following Python code (in a file called test.py
):
#!/usr/local/bin/python3
from wasmer import engine, Store, Module, Instance, wasi
from wasmer_compiler_cranelift import Compiler
if __name__ == "__main__":
r = open("parse.wasm", "rb")
store = Store(engine.JIT(Compiler))
module = Module(store, r.read())
wasi_version = wasi.get_version(module, strict=True)
wasi_env = wasi.StateBuilder('main'). \
argument('2022-01-01'). \
finalize()
import_object = wasi_env.generate_import_object(store, wasi_version)
instance = Instance(module, import_object)
instance.exports._start()
I get this:
$> /usr/local/opt/[email protected]/bin/python3.10 ./test.py
2022-01-01
However, it's not clear how I can capture that output to a variable. Swapping out sys.stdout
(or stderr
) to a StringIO
instance doesn't seem to work.
If I modify the code to pass an input pointer to instance.exports.parse
like this:
#!/usr/local/bin/python3
from wasmer import engine, Store, Module, Instance, wasi
from wasmer_compiler_cranelift import Compiler
if __name__ == "__main__":
r = open("parse.wasm", "rb")
store = Store(engine.JIT(Compiler))
module = Module(store, r.read())
wasi_version = wasi.get_version(module, strict=True)
wasi_env = wasi.StateBuilder('main'). \
finalize()
import_object = wasi_env.generate_import_object(store, wasi_version)
instance = Instance(module, import_object)
input = bytes('2022-01-01', 'utf-8')
input_len = len(input)
input_pointer = instance.exports.malloc(input_len)
memory = instance.exports.memory.uint8_view(input_pointer)
memory[0:input_len] = input
memory[input_len] = 0
instance.exports.parse(input_pointer)
I get the following error:
$> /usr/local/opt/[email protected]/bin/python3.10 ./test.py
Traceback (most recent call last):
File "/usr/local/sfomuseum/go-edtf/./test.py", line 35, in <module>
instance.exports.parse(input_pointer)
RuntimeError: RuntimeError: Parameters of type [I32] did not match signature [I32, I32, I32] -> []
Which I understand in principle but I am not sure I understand what is triggering it or why since it does not match the signature of the parse
method in Go:
https://github.com/sfomuseum/go-edtf/blob/wasi/cmd/parse-wasi/main.go#L34
I feel like maybe I missing something obvious but I can't figure out what.
I was able to capture the output via this solution: https://stackoverflow.com/a/29834357
out = OutputGrabber()
with out:
instance.exports._start()
print(out.capturedtext)
That's very interesting and I will investigate shortly. Thanks!
It works! Thanks again.
https://github.com/sfomuseum/go-edtf-wasm/blob/wasi/python/test-wasmer.py