Skip to content

Operations

What are operations?

With client-server communication, Hoist has two fundamental items, the first being operations, and the second one being messages, which we will talk about more later.

Think of an operation like a function call. We send a name and some data to the server, and then it sends back the response.

An operation could look like this:

sequenceDiagram
    Client->>Server: Execute operation x with data {...}
    alt Error Occured
        Server->>Client: Error occured while executing: {...}
    else
        Server->>Client: Response of operation is ...
    end

Whitelisting and Blacklisting

Hoist comes with some operations out of the box. By default, all of these are enabled.

To blacklist one, pass its name to the unsupported_operations keyword argument:

import hoist

server = hoist.start(unsupported_operations=("print",))
# all operations work except print

If you would like a whilelist instead, pass the whitelisted names to the supported_operations argument:

import hoist

server = hoist.start(supported_operations=("print",))
# no operations work except print

You may also disable all operations by passing a sequence (such as tuple) containing "*":

import hoist

server = hoist.start(unsupported_operations=("*",))

Custom Operations

We can define operations ourself by using the operation decorator.

Here's a quick example:

import hoist

server = hoist.start(...)

@server.operation("my custom operation")
async def operation():
    return "hello world"

This isn't very useful though, since we aren't getting any arguments from the user.

Getting Parameters

Hoist will try to figure out what parameters you want based off the signature of the function.

The recommended way to is to use type hints, but you can do it without them.

Server and Payload

import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(server: hoist.Server, payload: dict):
    ...
import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(server, payload):
    ...

Server Only

import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(server: hoist.Server):
    ...

Payload Only

import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(payload: dict):
    ...
import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(payload):
    ...

Dynamic Parameters

import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(a: str):
    ...
import hoist

server = hoist.start(...)

@server.operation("...")
async def operation(a, b, c):
    ...

Warning

You must have 3 or more parameters when you aren't using type hints, otherwise Hoist will interpret as one of the above.

Payload Validation

You can hint a dataclass (such as NamedTuple) as your payload to get Hoist to validate the sent payload.

Note

Hoist uses the __annotations__ attribute to create schemas for validation. Any custom payload object should contain that with corresponding attributes.

Here's an example:

import hoist
from typing import NamedTuple

server = hoist.start(...)

class MyPayload(NamedTuple):
    a: str
    b: int

@server.operation("...")
async def operation(payload: MyPayload):
    ...

The above would make Hoist ensure that the payload sent by the client looks like this:

{
    "a": "...", // any string
    "b": 0 // any number
}