Skip to content

pytauri.ipc

tauri::ipc

Classes:

Name Description
ArgumentsType

The bound arguments of a command.

Invoke
InvokeResolver
ParametersType

The parameters of a command.

InvokeException

Indicates that an exception occurred in a command. Similar to Rust's Result::Err.

Commands

This class provides features similar to tauri::generate_handler.

JavaScriptChannelId

This class is a wrapper around pytauri.ffi.ipc.JavaScriptChannelId.

Channel

This class is a wrapper around pytauri.ffi.ipc.Channel.

Attributes:

Name Type Description
Headers

Headers module-attribute

Headers = TypeAliasType('Headers', list[tuple[bytes, bytes]])

http::header::HeaderMap::iter

(key, value) pairs of headers.

Each key will be yielded once per associated value. So, if a key has 3 associated values, it will be yielded 3 times.

[(b"key0", b"value00"), (b"key0", b"value01"), (b"key1", b"value1")]

Tip

You can use libraries like multidict or httpx.Headers to convert it into dict for more efficient retrieval of a specific header.

__all__ module-attribute

__all__ = ['ArgumentsType', 'Channel', 'Commands', 'Headers', 'Invoke', 'InvokeException', 'InvokeResolver', 'JavaScriptChannelId', 'ParametersType']

ArgumentsType

Bases: TypedDict

The bound arguments of a command.

Each key is optional, depending on the keys of the bound ParametersType.

You can use it like **kwargs, for example command(**arguments).

Attributes:

Name Type Description
body bytes

The body of this ipc message.

app_handle AppHandle

The handle of the app.

webview_window WebviewWindow

The WebviewWindow of this Invoke.

headers Headers

The headers of this ipc message.

body instance-attribute

body: bytes

The body of this ipc message.

app_handle instance-attribute

app_handle: AppHandle

The handle of the app.

webview_window instance-attribute

webview_window: WebviewWindow

The WebviewWindow of this Invoke.

headers instance-attribute

headers: Headers

The headers of this ipc message.

Invoke

tauri::ipc::Invoke

Methods:

Name Description
bind_to

Consumes this Invoke and binds parameters.

resolve

Consumes this Invoke and resolves the command with the given value.

reject

Consumes this Invoke and rejects the command with the given value.

Attributes:

Name Type Description
command str

The name of the current command.

command property

command: str

The name of the current command.

bind_to

bind_to(parameters: ParametersType) -> Optional[InvokeResolver[_ArgumentsTypeVar]]

Consumes this Invoke and binds parameters.

If the frontend illegally calls the IPC, this method will automatically reject this Invoke and return None.

The return value InvokeResolver.arguments is not the same object as the input parameters.

Source code in python/pytauri/src/pytauri/ffi/ipc.py
def bind_to(
    self, parameters: ParametersType
) -> Optional["InvokeResolver[_ArgumentsTypeVar]"]:
    """Consumes this `Invoke` and binds parameters.

    If the frontend illegally calls the IPC,
    this method will automatically reject this `Invoke` and return `None`.

    The return value [InvokeResolver.arguments][pytauri.ffi.ipc.InvokeResolver.arguments]
    is not the same object as the input `parameters`.
    """

resolve

resolve(value: _InvokeResponseBody) -> None

Consumes this Invoke and resolves the command with the given value.

Parameters:

Name Type Description Default

value

_InvokeResponseBody

The value to resolve the command with.

  • If str, it will be serialized as JSON on the frontend.
  • If bytes, it will be sent as ArrayBuffer to the frontend.
required
Source code in python/pytauri/src/pytauri/ffi/ipc.py
def resolve(self, value: _InvokeResponseBody) -> None:
    """Consumes this `Invoke` and resolves the command with the given value.

    Args:
        value: The value to resolve the command with.

            - If `str`, it will be serialized as JSON on the frontend.
            - If `bytes`, it will be sent as `ArrayBuffer` to the frontend.
    """
    ...

reject

reject(value: str) -> None

Consumes this Invoke and rejects the command with the given value.

Source code in python/pytauri/src/pytauri/ffi/ipc.py
def reject(self, value: str) -> None:
    """Consumes this `Invoke` and rejects the command with the given value."""
    ...

InvokeResolver

Bases: Generic[_ArgumentsTypeVar]

tauri::ipc::InvokeResolver

Methods:

Name Description
resolve

Consumes this InvokeResolver and resolves the command with the given value.

reject

Consumes this InvokeResolver and rejects the command with the given value.

Attributes:

Name Type Description
arguments _ArgumentsTypeVar

The bound arguments of the current command.

arguments property

arguments: _ArgumentsTypeVar

The bound arguments of the current command.

resolve

resolve(value: _InvokeResponseBody) -> None

Consumes this InvokeResolver and resolves the command with the given value.

Parameters:

Name Type Description Default

value

_InvokeResponseBody

The value to resolve the command with.

  • If str, it will be serialized as JSON on the frontend.
  • If bytes, it will be sent as ArrayBuffer to the frontend.
required
Source code in python/pytauri/src/pytauri/ffi/ipc.py
def resolve(self, value: _InvokeResponseBody) -> None:
    """Consumes this `InvokeResolver` and resolves the command with the given value.

    Args:
        value: The value to resolve the command with.

            - If `str`, it will be serialized as JSON on the frontend.
            - If `bytes`, it will be sent as `ArrayBuffer` to the frontend.
    """

reject

reject(value: str) -> None

Consumes this InvokeResolver and rejects the command with the given value.

Source code in python/pytauri/src/pytauri/ffi/ipc.py
def reject(self, value: str) -> None:
    """Consumes this `InvokeResolver` and rejects the command with the given value."""
    ...

ParametersType

Bases: TypedDict

The parameters of a command.

All keys are optional, and values can be of any type. If a key exists, it will be assigned a value corresponding to ArgumentsType.

Attributes:

Name Type Description
body ReadOnly[Any]

Whatever. We just use the key, not the value.

app_handle ReadOnly[Any]

Whatever. We just use the key, not the value.

webview_window ReadOnly[Any]

Whatever. We just use the key, not the value.

headers ReadOnly[Any]

Whatever. We just use the key, not the value.

body instance-attribute

body: ReadOnly[Any]

Whatever. We just use the key, not the value.

app_handle instance-attribute

app_handle: ReadOnly[Any]

Whatever. We just use the key, not the value.

webview_window instance-attribute

webview_window: ReadOnly[Any]

Whatever. We just use the key, not the value.

headers instance-attribute

headers: ReadOnly[Any]

Whatever. We just use the key, not the value.

InvokeException

InvokeException(value: str)

Bases: Exception

Indicates that an exception occurred in a command. Similar to Rust's Result::Err.

When this exception is raised in a command, pytauri will return it to the frontend through Invoke.reject(value) and will not log the exception on the python side.

Attributes:

Name Type Description
value str

The error message that will be returned to the frontend.

Source code in python/pytauri/src/pytauri/ipc.py
def __init__(self, value: str) -> None:  # noqa: D107
    self.value = value

value instance-attribute

value: str = value

The error message that will be returned to the frontend.

Commands

Commands()

Bases: UserDict[str, _PyInvokHandleData]

This class provides features similar to tauri::generate_handler.

Typically, you would use Commands.command to register a command handler function. Then, use Commands.generate_handler to get an invoke_handler for use with BuilderArgs.

Methods:

Name Description
generate_handler

This method is similar to tauri::generate_handler.

wrap_pyfunc

Wrap a Callable to conform to the definition of PyHandlerType.

parse_parameters

Check the signature of a Callable and return the parameters.

set_command

Set a command handler.

command

A decorator to register a command handler.

Source code in python/pytauri/src/pytauri/ipc.py
def __init__(self) -> None:  # noqa: D107
    super().__init__()

    data = self.data

    async def _async_invoke_handler(invoke: Invoke) -> None:
        # NOTE:
        # - the implementer of this function must not raise exceptions
        # - and must ensure to fulfill `invoke/resolver`
        resolver = None
        try:
            command = invoke.command
            handler_data = data.get(command)
            if handler_data is None:
                invoke.reject(f"no python handler `{command}` found")
                return

            parameters = handler_data.parameters
            handler = handler_data.handler

            resolver = invoke.bind_to(parameters)
            if resolver is None:
                # `invoke` has already been rejected
                return

            try:
                resp = await handler(**resolver.arguments)
                # TODO, PERF: idk if this will block?
            except InvokeException as e:
                resolver.reject(e.value)
            except Exception as e:
                # # TODO: Should we return the traceback to the frontend?
                # # It might leak information.
                # from traceback import format_exc
                # resolver.reject(format_exc())
                _logger.exception(
                    f"invoke_handler {handler}: `{handler.__name__}` raised an exception",
                    exc_info=e,
                )
                resolver.reject(repr(e))
            else:
                resolver.resolve(resp)

        except Exception as e:
            msg = f"{_async_invoke_handler} implementation raised an exception, please report this as a pytauri bug"

            _logger.critical(msg, exc_info=e)
            if resolver is not None:
                resolver.reject(msg)
            else:
                invoke.reject(msg)
            raise

    self._async_invoke_handler = _async_invoke_handler

generate_handler

generate_handler(portal: BlockingPortal) -> _InvokeHandlerProto

This method is similar to tauri::generate_handler.

You can use this method to get invoke_handler for use with BuilderArgs.

Examples:

from anyio.from_thread import start_blocking_portal

commands = Commands()

with start_blocking_portal(backend) as portal:
    invoke_handler = commands.generate_handler(portal)
    ...

Warning

The portal must remain valid while the returned invoke_handler is being used.

Source code in python/pytauri/src/pytauri/ipc.py
def generate_handler(self, portal: BlockingPortal, /) -> _InvokeHandlerProto:
    """This method is similar to [tauri::generate_handler](https://docs.rs/tauri/latest/tauri/macro.generate_handler.html).

    You can use this method to get `invoke_handler` for use with [BuilderArgs][pytauri.BuilderArgs].

    Examples:
        ```py
        from anyio.from_thread import start_blocking_portal

        commands = Commands()

        with start_blocking_portal(backend) as portal:
            invoke_handler = commands.generate_handler(portal)
            ...
        ```

    !!! warning
        The `portal` must remain valid while the returned `invoke_handler` is being used.
    """
    async_invoke_handler = self._async_invoke_handler

    def invoke_handler(invoke: Invoke) -> None:
        # NOTE:
        # - `invoke_handler` must not raise exception
        # - must not block

        # this func will be call in extern thread, so it's ok to use `start_task_soon`
        portal.start_task_soon(async_invoke_handler, invoke)

    return invoke_handler

wrap_pyfunc staticmethod

wrap_pyfunc(pyfunc: _WrappablePyHandlerType) -> _PyHandlerType

Wrap a Callable to conform to the definition of PyHandlerType.

Specifically:

  • If pyfunc has a KEYWORD_ONLY parameter named body:
    • If body is bytes: do nothing.
    • If issubclass(body, BaseModel): wrap this callable as a new function with a body: bytes parameter.
    • Otherwise: try to convert it to a BaseModel/TypeAdapter, and proceed as in the BaseModel branch.
  • Handle the return type:
    • If the return type is bytes: do nothing.
    • If issubclass(return_type, BaseModel): wrap this callable as a new function with return: str value.
    • Otherwise: try to convert it to a BaseModel/TypeAdapter, and proceed as in the BaseModel branch.
  • If no wrapping is needed, the original pyfunc will be returned.

The pyfunc will be decorated using functools.wraps, and its __signature__ will also be updated.

Source code in python/pytauri/src/pytauri/ipc.py
@staticmethod
def wrap_pyfunc(  # noqa: C901, PLR0912, PLR0915  # TODO: simplify this method
    pyfunc: _WrappablePyHandlerType,
) -> _PyHandlerType:
    """Wrap a `Callable` to conform to the definition of PyHandlerType.

    Specifically:

    - If `pyfunc` has a `KEYWORD_ONLY` parameter named `body`:
        - If `body` is `bytes`:
            do nothing.
        - If `issubclass(body, BaseModel)`:
            wrap this callable as a new function with a `body: bytes` parameter.
        - Otherwise:
            try to convert it to a `BaseModel`/`TypeAdapter`, and proceed as in the `BaseModel` branch.
    - Handle the return type:
        - If the return type is `bytes`:
            do nothing.
        - If `issubclass(return_type, BaseModel)`:
            wrap this callable as a new function with `return: str` value.
        - Otherwise:
            try to convert it to a `BaseModel`/`TypeAdapter`, and proceed as in the `BaseModel` branch.
    - If no wrapping is needed, the original `pyfunc` will be returned.

    The `pyfunc` will be decorated using [functools.wraps][], and its `__signature__` will also be updated.
    """
    serializer: Optional[_Serializer[Union[BaseModel, Any]]] = None
    deserializer: Optional[_Deserializer[Union[BaseModel, Any]]] = None

    body_key = "body"

    sig = signature(pyfunc)
    parameters = sig.parameters
    return_annotation = sig.return_annotation

    body_param = parameters.get(body_key)
    if body_param is not None:
        if body_param.kind not in {
            Parameter.KEYWORD_ONLY,
            Parameter.POSITIONAL_OR_KEYWORD,
        }:
            raise ValueError(
                f"Expected `{body_key}` to be KEYWORD parameter, but got `{body_param.kind}` parameter"
            )

        body_type = body_param.annotation
        if body_type is Parameter.empty:
            raise ValueError(
                f"Expected `{body_key}` to have type annotation, but got empty"
            )
        elif body_type is bytes:
            serializer = None
        # `Annotated`, `Union`, `None`, etc are not `type`
        elif isinstance(body_type, type) and issubclass(body_type, BaseModel):
            serializer = body_type.model_validate_json
        else:
            # PERF, FIXME: `cast` make pyright happy, it mistakenly thinks this is `Any | type[Unknown]`
            body_type = cast(Any, body_type)
            try:
                serializer = _type_to_model(body_type).serializer
            except Exception as e:
                raise ValueError(
                    f"Failed to convert `{body_type}` type to pydantic Model, "
                    f"please explicitly use {BaseModel} or {bytes} as `{body_key}` type annotation instead."
                ) from e

    if return_annotation is Signature.empty:
        raise ValueError(
            "Expected the return value to have type annotation, but got empty. "
            "Please explicitly use `def foo() -> None:` instead."
        )
    elif return_annotation is bytes:
        deserializer = None
    # `Annotated`, `Union`, `None`, etc are not `type`
    elif isinstance(return_annotation, type) and issubclass(
        return_annotation, BaseModel
    ):
        # PERF: maybe we should cache this closure?
        def _deserializer(data: BaseModel) -> str:
            return data.model_dump_json()

        deserializer = _deserializer
    else:
        # PERF, FIXME: `cast` make pyright happy, it mistakenly thinks this is `Any | type[Unknown]`
        return_annotation = cast(Any, return_annotation)
        try:
            deserializer = _type_to_model(return_annotation).deserializer
        except Exception as e:
            raise ValueError(
                f"Failed to convert `{return_annotation}` type to pydantic Model, "
                f"please explicitly use {BaseModel} or {bytes} as return type annotation instead."
            ) from e

    if not serializer and not deserializer:
        return cast(_PyHandlerType, pyfunc)  # `cast` make typing happy

    @wraps(pyfunc)
    async def wrapper(*args: Any, **kwargs: Any) -> _InvokeResponseBody:
        nonlocal serializer, deserializer

        if serializer is not None:
            body_bytes = kwargs[body_key]
            assert isinstance(body_bytes, bytes)  # PERF
            try:
                body_arg = serializer(body_bytes)
            except ValidationError as e:
                raise InvokeException(repr(e)) from e
            kwargs[body_key] = body_arg

        resp = await pyfunc(*args, **kwargs)

        if deserializer is not None:
            # - subclass of `BaseModel`
            # - other types that are not `bytes`
            assert not isinstance(resp, bytes)  # PERF
            return deserializer(resp)
        else:
            assert isinstance(resp, bytes)  # PERF
            return resp

    new_parameters = parameters.copy()
    new_return_annotation = return_annotation
    if serializer is not None:
        new_parameters[body_key] = parameters[body_key].replace(annotation=bytes)
    if deserializer is not None:
        new_return_annotation = str

    # see: <https://docs.python.org/3.13/library/inspect.html#inspect.signature>
    wrapper.__signature__ = sig.replace(  # pyright: ignore[reportAttributeAccessIssue]
        parameters=tuple(new_parameters.values()),
        return_annotation=new_return_annotation,
    )
    return wrapper

parse_parameters staticmethod

parse_parameters(pyfunc: _PyHandlerType, /, check_signature: bool = True) -> ParametersType

Check the signature of a Callable and return the parameters.

Check if the Signature of pyfunc conforms to ArgumentsType, and if the return value is bytes or str.

Parameters:

Name Type Description Default

pyfunc

_PyHandlerType

The Callable to check.

required

check_signature

bool

Whether to check the signature of pyfunc. Set it to False only if you are sure that the signature conforms to the expected pattern.

True

Returns:

Type Description
ParametersType

The parameters of the pyfunc. You can use it with Invoke.bind_to.

Raises:

Type Description
ValueError

If the signature does not conform to the expected pattern.

Source code in python/pytauri/src/pytauri/ipc.py
@staticmethod
def parse_parameters(
    pyfunc: _PyHandlerType, /, check_signature: bool = True
) -> ParametersType:
    """Check the signature of a `Callable` and return the parameters.

    Check if the [Signature][inspect.Signature] of `pyfunc` conforms to [ArgumentsType][pytauri.ipc.ArgumentsType],
    and if the return value is [bytes][] or [str][].

    Args:
        pyfunc: The `Callable` to check.
        check_signature: Whether to check the signature of `pyfunc`.
            Set it to `False` only if you are sure that the signature conforms to the expected pattern.

    Returns:
        The parameters of the `pyfunc`. You can use it with [Invoke.bind_to][pytauri.ipc.Invoke.bind_to].

    Raises:
        ValueError: If the signature does not conform to the expected pattern.
    """
    sig = signature(pyfunc)
    parameters = sig.parameters
    if not check_signature:
        # `cast` make typing happy
        return cast(ParametersType, parameters)

    return_annotation = sig.return_annotation

    arguments_type = {
        "body": bytes,
        "app_handle": AppHandle,
        "webview_window": WebviewWindow,
        "headers": Headers,
    }

    for name, param in parameters.items():
        # check if the `parameters` type hint conforms to [pytauri.ipc.ArgumentsType][]

        correct_anna = arguments_type.get(name)
        if correct_anna is None:
            raise ValueError(
                f"Unexpected parameter `{name}`, expected one of {list(arguments_type.keys())}"
            )
        if param.annotation is not correct_anna:
            raise ValueError(
                f"Expected `{name}` to be `{correct_anna}`, but got `{param.annotation}`"
            )
        if param.kind not in {
            Parameter.KEYWORD_ONLY,
            Parameter.POSITIONAL_OR_KEYWORD,
        }:
            raise ValueError(
                f"Expected `{name}` to be KEYWORD parameter, but got `{param.kind}` parameter"
            )
    else:
        # after checking, we are sure that the `parameters` are valid
        parameters = cast(ParametersType, parameters)

    if return_annotation not in {bytes, str}:
        raise ValueError(
            f"Expected `return_annotation` to be {bytes} or {str}, got `{return_annotation}`"
        )

    return parameters

set_command

set_command(command: str, handler: _WrappablePyHandlerType, /, check_signature: bool = True) -> None

Set a command handler.

This method internally calls parse_parameters and wrap_pyfunc, parse_parameters(wrap_pyfunc(handler)).

Source code in python/pytauri/src/pytauri/ipc.py
def set_command(
    self,
    command: str,
    handler: _WrappablePyHandlerType,
    /,
    check_signature: bool = True,
) -> None:
    """Set a command handler.

    This method internally calls [parse_parameters][pytauri.Commands.parse_parameters]
    and [wrap_pyfunc][pytauri.Commands.wrap_pyfunc], `parse_parameters(wrap_pyfunc(handler))`.
    """
    new_handler = self.wrap_pyfunc(handler)
    parameters = self.parse_parameters(new_handler, check_signature=check_signature)
    self.data[command] = _PyInvokHandleData(parameters, new_handler)

command

command(command: Optional[str] = None) -> _RegisterType[_WrappablePyHandlerTypeVar]

A decorator to register a command handler.

Examples:

commands = Commands()


@commands.command()
async def my_command(body: FooModel, app_handle: AppHandle) -> BarModel: ...


@commands.command("foo_command")
async def my_command2(body: FooModel, app_handle: AppHandle) -> BarModel: ...

This method internally calls set_command, which means the function signature must conform to ArgumentsType.

Parameters:

Name Type Description Default

command

Optional[str]

The name of the command. If not provided, the __name__ of callable will be used.

None

Raises:

Type Description
ValueError

If a command with the same name already exists. If it's expected, use set_command instead.

Source code in python/pytauri/src/pytauri/ipc.py
def command(
    self, command: Optional[str] = None, /
) -> _RegisterType[_WrappablePyHandlerTypeVar]:
    """A [decorator](https://docs.python.org/3/glossary.html#term-decorator) to register a command handler.

    Examples:
        ```py
        commands = Commands()


        @commands.command()
        async def my_command(body: FooModel, app_handle: AppHandle) -> BarModel: ...


        @commands.command("foo_command")
        async def my_command2(body: FooModel, app_handle: AppHandle) -> BarModel: ...
        ```

    This method internally calls [set_command][pytauri.Commands.set_command],
    which means the function signature must conform to [ArgumentsType][pytauri.ipc.ArgumentsType].

    Args:
        command: The name of the command. If not provided, the `__name__` of `callable` will be used.

    Raises:
        ValueError: If a command with the same name already exists.
            If it's expected, use [set_command][pytauri.Commands.set_command] instead.
    """
    if command is None:
        return self._register
    else:
        return partial(self._register, command=command)

JavaScriptChannelId

Bases: RootModel[_FFIJavaScriptChannelIdAnno], Generic[_ModelTypeVar]

This class is a wrapper around pytauri.ffi.ipc.JavaScriptChannelId.

You can use this class as model field in pydantic model directly, or use it as model directly.

pytauri.ffi.ipc.JavaScriptChannelId can't be used directly in pydantic model.

Examples

from asyncio import Task, create_task, sleep
from typing import Any

from pydantic import BaseModel, RootModel
from pydantic.networks import HttpUrl
from pytauri import Commands
from pytauri.ipc import JavaScriptChannelId, WebviewWindow

commands = Commands()

Progress = RootModel[int]


class Download(BaseModel):
    url: HttpUrl
    channel: JavaScriptChannelId[Progress]


background_tasks: set[Task[Any]] = set()


@commands.command()
async def download(body: Download, webview_window: WebviewWindow) -> None:
    channel = body.channel.channel_on(webview_window.as_ref_webview())

    async def task():
        progress = Progress(0)
        while progress.root <= 100:
            channel.send_model(progress)
            await sleep(0.1)
            progress.root += 1

    t = create_task(task())
    background_tasks.add(t)
    t.add_done_callback(background_tasks.discard)


# Or you can use it as `body` model directly
@commands.command()
async def my_command(body: JavaScriptChannelId) -> bytes: ...

Methods:

Name Description
from_str
channel_on

from_str classmethod

from_str(value: str) -> Self

See pytauri.ffi.ipc.JavaScriptChannelId.from_str.

Source code in python/pytauri/src/pytauri/ipc.py
@classmethod
def from_str(cls, value: str, /) -> Self:
    """See [pytauri.ffi.ipc.JavaScriptChannelId.from_str][]."""
    ffi_js_channel_id = _FFIJavaScriptChannelId.from_str(value)
    return cls(ffi_js_channel_id)

channel_on

channel_on(webview: Webview) -> Channel[_ModelTypeVar]

See pytauri.ffi.ipc.JavaScriptChannelId.channel_on.

Source code in python/pytauri/src/pytauri/ipc.py
def channel_on(self, webview: Webview, /) -> "Channel[_ModelTypeVar]":
    """See [pytauri.ffi.ipc.JavaScriptChannelId.channel_on][]."""
    ffi_channel = self.root.channel_on(webview)
    return Channel(ffi_channel)

Channel

Channel(ffi_channel: Channel)

Bases: Generic[_ModelTypeVar]

This class is a wrapper around pytauri.ffi.ipc.Channel.

It adds the following methods:

Examples

See JavaScriptChannelId

Methods:

Name Description
id
send
send_model

Equivalent to self.send(model.model_dump_json()).

Source code in python/pytauri/src/pytauri/ipc.py
def __init__(self, ffi_channel: _FFIChannel, /):  # noqa: D107
    self._ffi_channel = ffi_channel

id

id() -> int

See pytauri.ffi.ipc.Channel.id.

Source code in python/pytauri/src/pytauri/ipc.py
def id(self, /) -> int:
    """See [pytauri.ffi.ipc.Channel.id][]."""
    return self._ffi_channel.id()

send

send(data: _InvokeResponseBody) -> None

See pytauri.ffi.ipc.Channel.send.

Source code in python/pytauri/src/pytauri/ipc.py
def send(self, data: _InvokeResponseBody, /) -> None:
    """See [pytauri.ffi.ipc.Channel.send][]."""
    self._ffi_channel.send(data)

send_model

send_model(model: _ModelTypeVar) -> None

Equivalent to self.send(model.model_dump_json()).

Source code in python/pytauri/src/pytauri/ipc.py
def send_model(self, model: _ModelTypeVar, /) -> None:
    """Equivalent to `self.send(model.model_dump_json())`."""
    self.send(model.model_dump_json())