Dispatch

Usage

The library includes an optional system for dispatching incoming requests to handler functions and managing connection state. It can also help you generate documentation for your JSON-RPC API; see Sphinx Integration.

This system revolves around the Dispatch class. First, create a dispatch instance. Usually you would do this at the top-level of your server module.

from trio_jsonrpc import Dispatch

dispatch = Dispatch()

Now you can use this instance’s decorator to register Python functions as JSON-RPC methods.

@dispatch.handler
async def greet(name: str) -> dict:
    return {"greeting": "Hello, {}!".format(name)}

This decorator registers the greet(...) method as a JSON-RPC method named greet.

Note

Keep in mind that if you define your dispatch and your handlers in separate files, there will be a cyclical dependency between them. That’s OK, just make sure to import your handler modules after you create the dispatch instance. That won’t be PEP-8 compliant, but it is necessary.

Finally, your main server loop can dispatch incoming requests:

await dispatch.handle_request(request, result_send)

The result_send variable is the send side of a Trio channel. The server should read from the other side of the channel to gather the results from the various handler functions.

Context

It may be helpful to maintain some connection state that can be accessed or modified by the handler functions. The dispatch system allows for providing a custom object that is exposed to handler methods. To use dispatch context, you first need to declare a class that holds the connection state.

@dataclass
class ConnectionContext:
    name: typing.Optional[str] = None

This example uses Python’s dataclasses, which are convenient for this purpose. But any ordinary class will work, too. When your server receives a new connection, you should create an instance of this context object and expose it to the connection:

context = ConnectionContext()
async with dispatch.connection_context(context):
    # Handle connection here

The context manager Dispatch.connection_context() will set your connection context object to be used by all Trio tasks that execute within that block. Under the hood, this uses some magic with contextvars to ensure that all handlers on a given connection see the same instance.

Now you can write handler functions that access the dispatch context. Here’s an example that adapts the greet method presented in the previous section.

@dispatch.handler
async def set_name(name: str) -> None:
    dispatch.ctx.name = name

@dispatch.handler
async def greet() -> dict:
    return {"greeting": "Hello, {}!".format(dispatch.ctx.name)}

The dispatch.ctx object is the same object that you passed into connection_context. This allows all handlers to easily access the connection context.

API

class trio_jsonrpc.Dispatch

This class assists with dispatching JSON-RPC methods to specific handler functions.

Each handler is registered using a decorator. When a method is executed on the dispatcher, it looks up the registered handler and calls it in a new task.

async with connection_context(context)

Set the connection context for the current task and all child tasks.

ctx

Get the connection context for the current task.

await execute(request: sansio_jsonrpc.main.JsonRpcRequest) → Any

A helper for running a single JSON-RPC command and getting the result.

This is mainly helpful for testing, since it returns the result directly rather than via channel.

Parameters

request

Returns

The result of the command.

Raises

JsonRpcException if the command returned an error.

get_handler(method: str)

Find the handler function for a given JSON-RPC method name.

await handle_request(request: sansio_jsonrpc.main.JsonRpcRequest, result_channel: trio.MemorySendChannel) → None

Dispatch a JSON-RPC request and send its result to the given channel.

Parameters
  • request

  • result_channel

Returns

The outcome of executing the JSON-RPC method, either a result or an error.

handler(fn)

A decorator that registers an async function as a handler.

Parameters

fn – The function to decorate.