Commands
INCOMPLETE DOCUMENTATION
These things are currently missing compared to the existing docs:
- Alternate Javascript import (window.__TAURI__.pytauri)
- More options for creating the app/ invoke_handler
Commands can be registered using the command handler decorator as seen below.
from pytauri import AppHandle, Commands
commands = Commands()
@commands.command()
async def fire_command(body: bytes) -> bytes:
pass
@commands.command()
async def fire_other_command(body: bytes, app_handle: AppHandle) -> bytes:
pass
To handle IPC correctly, the function follows strict rules:
- They must be asynchronous
- There must be a typed
body
argument of typebytes
(more on this later.) - An optional typed
app_handle
argument of typeAppHandle
can be used to get access to the current app handle instance. - The command must return type
bytes
Deserialization
Sending raw bytes is useful for images or files, however in most cases we want more readable information. Under the hood PyTauri uses Pydantic for deserializing the body of a command. This means that any RootmModel
or BaseModel
from Pydantic can also be used for typing either the body or return variable.
from pydantic import BaseModel, RootModel
from pytauri import AppHandle, Commands
commands = Commands()
class User(BaseModel):
name: str
email: str
Roles = RootModel[list[str]]
@commands.command()
async def get_user_roles(body: User) -> Roles:
pass
Registering the commands
In order to call the commands from the frontend, an async runtime is required. anyio.from_thread.start_blocking_portal is used as an example, but other equivalent functions can be used.
from anyio.from_thread import start_blocking_portal
from pytauri import BuilderArgs, Commands, builder_factory, context_factory
commands = Commands()
with start_blocking_portal("asyncio") as portal: # or "trio"
builder = builder_factory()
app = builder.build(
BuilderArgs(
context_factory(),
invoke_handler=commands.generate_handler(portal),
)
)
app.run()
Note that portal
should not be closed while the app is running.
Calling from the frontend
PyTauri has two functions for calling a command: pyInvoke
and rawPyInvoke
. rawPyInvoke
allows sending and receiving of binary data.
import {pyInvoke} from "tauri-plugin-pytauri-api";
interface User {
name: string;
email: string;
}
const user: User = {name: "John", email: "john@example.com"};
const output = await pyInvoke<string[]>("get_user_roles", user);
Returning errors to the frontend
Any [InvokeException]
raised in a command will automatically return the function with the supplied error message.
from pytauri import Commands
from pytauri.ipc import InvokeException
commands = Commands()
@commands.command()
async def invalid_user() -> bytes:
raise InvokeException("User not found")