Thing Slots

It is often desirable for two Things in the same server to be able to communicate. In order to do this in a nicely typed way that is easy to test and inspect, LabThings-FastAPI provides thing_slot. This allows a Thing to declare that it depends on another Thing being present, and provides a way for the server to automatically connect the two when the server is set up.

Thing connections are set up after all the Thing instances are initialised. This means you should not rely on them during initialisation: if you attempt to access a connection before it is available, it will raise an exception. The advantage of making connections after initialisation is that we don’t need to worry about the order in which Things are created.

The following example shows the use of a thing_slot:

import labthings_fastapi as lt


class ThingA(lt.Thing):
    "A class that doesn't do much."

    @lt.action
    def say_hello(self) -> str:
        "A canonical example function."
        return "Hello world."


class ThingB(lt.Thing):
    "A class that relies on ThingA."

    thing_a: ThingA = lt.thing_slot()

    @lt.action
    def say_hello(self) -> str:
        "I'm too lazy to say hello, ThingA does it for me."
        return self.thing_a.say_hello()


things = {"thing_a": ThingA, "thing_b": ThingB}
server = lt.ThingServer.from_things(things)

In this example, ThingB.thing_a is the simplest form of thing_slot: it is type hinted as a Thing subclass, and by default the server will look for the instance of that class and supply it when the server starts. If there is no matching Thing or if more than one instance is present, the server will fail to start with a ThingSlotError.

It is also possible to use an optional type hint (ThingA | None), which means there will be no error if a matching Thing instance is not found, and the slot will evaluate to None. Finally, a thing_slot may be type hinted as Mapping[str, ThingA] which permits zero or more instances to be connected. The mapping keys are the names of the things.

Configuring Thing Slots

A thing_slot may be given a default value. If this is a string, the server will look up the Thing by name. If the default is None the slot will evaluate to None unless explicitly configured.

Slots may also be specified in the server’s configuration: ThingConfig takes an argument that allows connections to be made by name (or set to None). The same field is present in a config file. Each entry in the things list may have a thing_slots property that sets up the connections. To repeat the example above with a configuration file:

"things": {
    "thing_a": "example:ThingA",
    "thing_b": {
        "class": "example:ThingB",
        "thing_slots": {
            "thing_a": "thing_a"
        }
    }
}

More detail can be found in the description of thing_slot or the thing_slots module documentation.