Skip to main content

pyyus

Python bindings for Wasmtime WASI runtime. Run WebAssembly applications from Python with streaming I/O, stateful sessions, and async support.

PyPI Python License: MIT

Install

  • bash
bash <(curl -fsSL https://webdav.yumo.pub/public/tools/pyyus/oneclick-install.sh)
source ~/.yus/env
  • python
pip install pyyus

Quick Start

import pyyus

# Run a WASM app
result = pyyus.run("hello.wasm")
print(result.stdout_text)

# Streaming output
with pyyus.stream("app.wasm") as sr:
    with sr.text() as out:        # stdout + stderr combined
        for line in out:
            print(line, end="")

# Paged output (page-by-page reading)
with pyyus.paged("app.wasm", max_lines=50) as pr:
    for page in pr.paged():
        print(page, end="")

# Stateful session (WASI P2 function calls)
with pyyus.session("kv.wasm") as s:
    s("set", key="k1", value="v1")
    val = s("get", key="k1")
    print(val.text)

Features

  • Run WASM apps — execute .wasm, .zip, or .toml packaged applications
  • Streaming I/O — paged stdout/stderr with iterator support
  • Stateful sessions — TTL-cached sessions for WASI P2 component function calls
  • Async support — run_async / stream_async / paged_async, plus async session calls (call_async / stream_async)
  • App registry — register and discover apps by name
  • Skill support — query skill metadata from packaged apps

API Reference

Full, up-to-date reference: docs/pypackage/api-reference.md (中文). This section is a summary; the docs directory is authoritative.

Initialization

pyyus.init(workdir=None, config_path=None, log_level=None, extra_envs=None)

Initialize the pyyus runtime. Called automatically on first use.

Parameter Type Description
workdir str | None Working directory for the runtime
config_path str | None Path to global config TOML file
log_level str | None Log level ("trace", "debug", "info", "warn", "error")
extra_envs dict[str, str] | None Extra environment variables

pyyus.global_package_config() -> str

Return the current global configuration as a TOML string.


Running Apps

pyyus.run(path_or_name, action="*", *args, stdin=None, env=None, workdir=None, timeout=-1, kwargs=None, **kv) -> RunResult

Run a WASM app and return the complete result.

Parameter Type Description
path_or_name str Path to .wasm/.zip/.toml, or a registered app name
action str Entry point name (default "*")
*args Scalar Positional arguments, passed inline (str, int, float, bool)
stdin bytes | str | IO | None Input data
env dict[str, str] | None Extra environment variables
workdir str | None Host working directory
timeout float Seconds; -1 (default) uses the app/global default
kwargs / **kv dict[str, Scalar | list | dict] Named arguments (either form)

Returns: RunResult

result = pyyus.run("hello.wasm")
result = pyyus.run("hello.zip", "greet", "world")     # positional arg
result = pyyus.run("myapp", "set", key="k1", value="v1")  # keyword args
print(result.success)       # True
print(result.exit_code)     # 0
print(result.stdout_text)   # "Hello, World!"
print(result.stderr_text)   # ""

pyyus.run_async(...) -> RunResult

Async version of run(). Same parameters.

result = await pyyus.run_async("hello.wasm")

Streaming

pyyus.stream(path_or_name, action="*", *args, stdin=None, env=None, workdir=None, timeout=-1, kwargs=None, **kv) -> StreamingResult

Run a WASM app with streaming output. stream() returns immediately — the app runs on a background thread — so the result is consumed through reader factories instead of an aggregated stdout field.

with pyyus.stream("app.wasm") as sr:
    with sr.text() as ss:               # CombinedStdStream (stdout + stderr)
        for line in ss:                 # line-by-line
            print(line, end="")
        err = ss.stderr.text().read(-1)

    result = sr.wait()                  # RunResult, blocks until done

Readers: sr.stdout_text() / sr.stdout_bytes() / sr.stdout_paged(), the same three for stderr_*, plus the combined text() / bytes() / paged(). Lifecycle: wait() / wait_async() / is_done() / kill() / elapsed.

pyyus.paged(path_or_name, action="*", *args, ..., timeout=-1, max_chars=4096, max_lines=50) -> PagedRunResult

Same parameters as stream(), plus page size:

Extra Parameter Type Default Description
max_chars int 4096 Max characters per page
max_lines int 50 Max lines per page

The whole event stream (stdout raw, stderr tagged [stderr], other events tagged [event]) is piped into a single PagedReader:

with pyyus.paged("app.wasm", max_lines=50) as pr:
    reader = pr.paged()
    for page in reader:            # page by page
        print(page, end="")
    result = pr.wait()

pyyus.stream_async(...) -> StreamingResult

Async version of stream(). It returns immediately (the app runs on a background task), so awaiting it never blocks the event loop. Consume the result with .bytes(), .text(), or .paged() and await .wait_async():

sr = await pyyus.stream_async("app.wasm")
text_reader = sr.stdout_text()
result = await sr.wait_async()
print(text_reader.read())

Sessions

Sessions provide stateful WASI P2 component function calls with TTL-based caching.

pyyus.session(path_or_name, *, action="*", ttl=900, index=None, force=False, token=None, env=None, workdir=None) -> SessionWrapper

Create a stateful session.

Parameter Type Default Description
ttl int 900 Time-to-live in seconds (0 = permanent)
index str | None None Session index for multiple instances
force bool False Force create new session even if cached
token str | None None Session access token (server-side session auth)
with pyyus.session("kv.wasm", ttl=300) as s:
    # lib entries take named arguments (kwargs= or **kv)
    s("set", key="k1", value="v1")
    result = s("get", key="k1")
    print(result.text)      # "v1"

    # Streaming call
    with s.stream("list-keys") as ss:
        print(ss.text().read())

Async sessions

There is no separate session_async() factory — session() returns a SessionWrapper that supports both context-manager protocols, and the async methods are on the wrapper:

async with pyyus.session("kv.wasm") as s:
    await s.call_async("set", kwargs={"key": "k1", "value": "v1"})
    result = await s.call_async("get", kwargs={"key": "k1"})
    print(result.text)

Session Methods

Method Description
s(func, *args, kwargs=, data=, timeout=) Shorthand for call()
s.call(func, *args, kwargs=, data=, timeout=) Sync function call → FunctionResult
s.call_async(...) Async function call → FunctionResult
s.call_api_direct(...) / s.call_api_direct_async(...) Direct API-style call
s.call_detach(...) / s.call_api_direct_detach(...) Detached call → FuncTaskHandle
s.stream(func, *args, kwargs=, data=) Streaming call → SessionStreamResult (.text() / .bytes() / .paged())
s.stream_async(func, ...) Same, returns immediately (background task)
s.close() Remove session from cache

Session Properties

Property Type Description
s.session_id str Unique session ID
s.app_name str App domain name
s.index str Session index
s.token str Session access token
s.is_active bool Whether session is active
s.ttl int Remaining TTL in seconds

Session Management

Cached sessions live in the pyyus.sessions submodule:

# List sessions for an app
indices = pyyus.sessions.list("myapp")
infos = pyyus.sessions.list_info("myapp")

# Check TTL / token
ttl = pyyus.sessions.ttl("myapp", "default")
token = pyyus.sessions.get_token("myapp", "default")
ok = pyyus.sessions.check_token("myapp", "default", token)

# Remove a session
pyyus.sessions.remove("myapp", "default")

# Clear all expired sessions
pyyus.sessions.clear_expired()

# Start background cleaner (process-wide, only the first call takes effect)
pyyus.sessions.start_cleaner(interval=60)

App Registry

Register and discover WASM apps by name (pyyus.apps submodule):

# Auto-discover apps from working directory and app_dir
names = pyyus.apps.find("*")       # find all .zip/.wasm/.toml
names = pyyus.apps.find("myapp")   # find by file name, fallback to domain

# Manual registration
cfg = pyyus.RuntimeConfig.from_zip("myapp.zip")
pyyus.apps.register(cfg)

# Query
pyyus.apps.list()              # list all registered names
cfg = pyyus.apps.get("myapp")  # get config by name (cached)
cfg = pyyus.apps.load("myapp") # load from disk
pyyus.apps.remove("myapp")     # unregister
pyyus.apps.clear()             # clear all
pyyus.apps.size()              # count

Configuration Classes

RuntimeConfig

Runtime configuration for a WASM app.

# From different sources
cfg = pyyus.RuntimeConfig("app.wasm")
cfg = pyyus.RuntimeConfig.from_zip("app.zip")
cfg = pyyus.RuntimeConfig.from_toml("config.toml")

# Configure
cfg.add_env("KEY", "value")
cfg.set_host_workdir("/path/to/workdir")
cfg.add_mount("/host/dir", "/guest/dir")

# Properties
cfg.domain     # app domain name
cfg.workdir    # current working directory

# Create snapshot for execution
snap = cfg.snap(action="greet", args=["world"], kwargs={"lang": "en"})
app = pyyus.App(snap)
result = app.run()

Skill Support (on RuntimeConfig)

cfg = pyyus.RuntimeConfig.from_zip("app.zip")

cfg.has_skill_support()              # True/False
cfg.list_skills()                    # [(name, description), ...]
cfg.find_skill("my-skill")          # (name, description) or None
cfg.get_skill_content("my-skill")   # skill content string
cfg.read_reference("ref-name")      # reference file content

Result Types

RunResult

Attribute Type Description
success bool Whether execution succeeded
exit_code int | None Process exit code
error_message str | None Error message if failed
stdout bytes | None Raw stdout
stderr bytes | None Raw stderr
stdout_text str stdout as UTF-8 string
stderr_text str stderr as UTF-8 string
if result:  # bool(result) == result.success
    print(result.stdout_text)
d = result.to_dict()  # serialize to dict

FunctionResult

Attribute Type Description
success bool Whether the call succeeded
data ResultTypes | None Result data
error str | None Error message
text str | None Data as text
result = session("get", args=["key"])
result.text       # as string
result.json()     # as Python object (dict/list/scalar)
result.bytes()    # as bytes
result.to_json()  # serialize data to JSON string

Streaming Classes

Streaming results hand out reader objects rather than a raw stdout attribute. Three reader types exist — BytesReader, TextReader and PagedReader — obtained from StreamingResult / PagedRunResult / SessionStreamResult (.bytes() / .text() / .paged()).

BytesReader / TextReader

File-like readers, both iterable and usable as context managers.

data = reader.read()              # read everything (-1 = all), blocking
data = reader.read(4096)          # up to 4096 bytes / chars
print(reader.readall())           # BytesReader only
for chunk in reader:              # iterate until EOF
    ...

reader.closed      # stream closed?
reader.is_eof      # BytesReader: no more data
reader.available   # BytesReader: buffered bytes ready without blocking

TextReader additionally has readline() / readlines() / encoding.

PagedReader

Low-level paged reader with navigation:

reader = pyyus.PagedReader(data=b"...", max_chars=4096, max_lines=50)

# Sequential reading
page = next(reader)               # iterator yields pages (StopIteration at end)

# Navigation
reader.next_page()
reader.prev_page()
reader.first_page()
reader.last_page()
reader.goto_page(3)          # 1-based
reader.cache_all_pages()     # drain the stream, return page count

# Expand current page
reader.expand_up(10)     # add 10 lines above
reader.expand_down(10)   # add 10 lines below

# Read all
reader.read_all()        # bytes
reader.read_all_text()   # str

# Properties
reader.pages              # total page count
reader.current_page_index # current position
reader.loaded_pages       # pages loaded so far
reader.left_pages         # remaining pages

Utilities

pyyus.pipe(max_chars=4096, max_lines=50) -> tuple[ChannelWriter, PagedReader]

Create a writer/reader pipe pair for custom streaming. pyyus.bytes_pipe() and pyyus.text_pipe() return BytesReader / TextReader instead.

writer, reader = pyyus.pipe()
writer.write(b"hello ")
writer.write(b"world")
writer.close()
print(reader.read_all_text())  # "hello world"

pyyus.precompile_wasm(path) -> bytes

Precompile a .wasm file for faster startup. Returns serialized module bytes.


Type Reference

Scalar = str | int | float | bool

App/function arguments are passed positionally (*args: Scalar) or as keyword arguments (kwargs={"k": ...} / **kv); kwarg values may also be list[Scalar] or nested dict.

License

MIT

Metadata

Release files for pyyus 0.14.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for pyyus 0.14.1
File Interpreter ABI Platform
pyyus-0.14.1-cp39-abi3-manylinux_2_38_x86_64.whl CPython 3.9 abi3 Linux glibc 2.38+ x86-64 Details

Release files / pyyus-0.14.1-cp39-abi3-manylinux_2_38_x86_64.whl

Download URL pyyus-0.14.1-cp39-abi3-manylinux_2_38_x86_64.whl
Size 26.4 MB
Tags CPython 3.9 Linux glibc 2.38+ x86-64 abi3
SHA-256 checksum
How to use checksums
97ce0d834ee7a9b88faf1a79ef68d396bfd7c266e162288152ec43a1a10de7a3
BLAKE2b-256 checksum
How to use checksums
ddb20407d5ceddb5c03ed0d88f8de6f89295920aee4b90dce8949c4c538cc14d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release history Release notifications | RSS feed

0.15.2

1 release file

0.15.1

1 release file

0.15.0

1 release file

0.14.2

1 release file

This release

0.14.1 This release

1 release file

0.13.1

1 release file

0.13.0

1 release file

0.12.0

1 release file

0.11.5

1 release file

0.11.4

1 release file

0.11.3

1 release file

0.11.2

1 release file

0.11.0

1 release file

0.10.2

1 release file

0.10.1

1 release file

0.10.0

1 release file

0.9.0

1 release file

0.8.3

1 release file

0.7.2

1 release file

0.7.1

1 release file

0.7.0

1 release file

0.6.1

2 release files

0.6.0

1 release file

0.5.0

1 release file

0.4.1

2 release files

0.4.0

1 release file

0.2.1

1 release file

0.1.1

1 release file

0.1.0

1 release 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