wasmer-python icon indicating copy to clipboard operation
wasmer-python copied to clipboard

Capturing output from WASI binary (produced by TinyGo 0.26.0)

Open thisisaaronland opened this issue 1 year ago • 3 comments

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.

thisisaaronland avatar Nov 24 '22 02:11 thisisaaronland