labthings_fastapi
LabThings-FastAPI.
This is the top level module for LabThings-FastAPI, a library for building Web of Things Core Concepts devices using Python. There is documentation on readthedocs, and the recommended place to start is labthings_fastapi.
This module contains a number of convenience imports and is intended to be imported using:
import labthings_fastapi as lt
The example code elsewhere in the documentation generally follows this convention. Symbols in the top-level module mostly exist elsewhere in the package, but should be imported from here as a preference, to ensure code does not break if modules are rearranged.
Submodules
- labthings_fastapi.actions
- labthings_fastapi.client
- labthings_fastapi.decorators
- labthings_fastapi.dependencies
- labthings_fastapi.deps
- labthings_fastapi.descriptors
- labthings_fastapi.example_things
- labthings_fastapi.exceptions
- labthings_fastapi.notifications
- labthings_fastapi.outputs
- labthings_fastapi.server
- labthings_fastapi.thing
- labthings_fastapi.thing_description
- labthings_fastapi.types
- labthings_fastapi.utilities
- labthings_fastapi.websockets
Classes
Represents a Thing, as defined by the Web of Things standard. |
|
A property that can be accessed via the HTTP API. |
|
A |
|
Use FastAPI to serve |
|
A client for a LabThings-FastAPI Thing. |
Functions
|
Mark a method of a Thing as a LabThings Property. |
|
Mark a method of a Thing as a LabThings Setting. |
|
Mark a method of a |
|
Mark a function as a FastAPI endpoint without making it an action. |
|
Retrieve a blocking portal from a Thing. |
Package Contents
- class labthings_fastapi.Thing
Represents a Thing, as defined by the Web of Things standard.
This class should encapsulate the code that runs a piece of hardware, or provides a particular function - it will correspond to a path on the server, and a Thing Description document.
Subclassing Notes
__init__: You should accept any arguments you need to configure the Thingin
__init__. Don’t initialise any hardware at this time, as your Thing may be instantiated quite early, or even at import time.
__enter__(self)and__exit__(self, exc_t, exc_v, exc_tb)are where youshould start and stop communications with the hardware. This is Python’s “context manager” protocol. The arguments of
__exit__will beNoneexcept after errors. You should be safe to ignore them, and just include code that will close down your hardware, which is equivalent to afinally:block.
- Properties and Actions are defined using decorators: the :deco:`.thing_action`
decorator declares a method to be an action, which will run when it’s triggered, and the :deco:`.thing_property` decorator (or
ThingPropertydescriptor) does the same for a property. See the documentation on those functions for more detail.
titlewill be used in various places as the human-readable name of your Thing,so it makes sense to set this in a subclass.
There are various LabThings methods that you should avoid overriding unless you know what you are doing: anything not mentioned above that’s defined in
Thingis probably best left alone. They may in time be collected together into a single object to avoid namespace clashes.- _labthings_blocking_portal: anyio.from_thread.BlockingPortal | None = None
See Concurrency in LabThings-FastAPI for why blocking portal is needed.
- async __aenter__() typing_extensions.Self
Context management is used to set up/close the thing.
As things (currently) do everything with threaded code, we define async
__aenter__and__aexit__wrappers to call the synchronous code, if it exists.- Returns:
this object.
- async __aexit__(exc_t: Any | None, exc_v: Any | None, exc_tb: Any) None
Wrap context management functions, if they exist.
See
__aenter__for more details.- Parameters:
exc_t – The type of the exception, or
None.exc_v – The exception that occurred, or
None.exc_tb – The traceback for the exception, or
None.
- attach_to_server(server: labthings_fastapi.server.ThingServer, path: str, setting_storage_path: str) None
Attach this thing to the server.
Things need to be attached to a server before use to function correctly.
- Parameters:
server – The server to attach this Thing to.
path – The root URL for the Thing.
setting_storage_path – The path on disk to save the any Thing Settings to. This should be the path to a json file. If it does not exist it will be created.
Attaching the
Thingto aThingServerallows theThingto start actions, load its settings from the correct place, and create HTTP endpoints to allow it to be accessed from the HTTP API.We create HTTP endpoints for all Interaction Affordances on the
Thing, as well as anyEndpointDescriptordescriptors.
- property _settings: dict[str, labthings_fastapi.descriptors.ThingSetting]
A private property that returns a dict of all settings for this Thing.
Each dict key is the name of the setting, the corresponding value is the ThingSetting class (a descriptor). This can be used to directly get the descriptor so that the value can be set without emitting signals, such as on startup.
- property setting_storage_path: str | None
The storage path for settings.
Note
This is set in
Thing.attach_to_server. It isNoneduring the__init__method, so it is best to avoid using settings until theThingis set up in__enter__.
- load_settings(setting_storage_path: str) None
Load settings from json.
Read the JSON file and use it to populate settings.
Note
Settings are loaded when the Thing is added to a server, so they will not be available while the
__init__method is run.Note that no notifications will be triggered when the settings are set, so if action is needed (e.g. updating hardware with the loaded settings) it should be taken in
__enter__.- Parameters:
setting_storage_path – The path where the settings should be stored.
- save_settings()
Save settings to JSON.
This is called whenever a setting is updated. All settings are written to the settings file every time.
- property thing_state: collections.abc.Mapping
Return a dictionary summarising our current state.
This is intended to be an easy way to collect metadata from a Thing that summarises its state. It might be used, for example, to record metadata along with each reading/image/etc. when an instrument is saving data.
It’s best to populate this automatically so it can always be accessed. If it requires calls e.g. to a serial instrument, bear in mind it may be called quite often and shouldn’t take too long.
Some measure of caching here is a nice aim for the future, but not yet implemented.
- _cached_thing_description: tuple[str | None, str | None, labthings_fastapi.thing_description._model.ThingDescription] | None = None
- thing_description(path: str | None = None, base: str | None = None) labthings_fastapi.thing_description._model.ThingDescription
Generate a w3c Thing Description representing this thing.
The w3c Web of Things working group defined a standard representation of a Thing, which provides a high-level description of the actions, properties, and events that it exposes. This endpoint delivers a JSON representation of the Thing Description for this Thing.
- Parameters:
path – the URL pointing to this Thing.
base – the base URL for all URLs in the thing description.
- Returns:
a Thing Description.
- thing_description_dict(path: str | None = None, base: str | None = None) dict
Describe this Thing with a Thing Description as a simple dict.
See
Thing.thing_description. This function converts the return value of that function into a simple dictionary.- Parameters:
path – the URL pointing to this Thing.
base – the base URL for all URLs in the thing description.
- Returns:
a Thing Description.
- observe_property(property_name: str, stream: anyio.abc.ObjectSendStream) None
Register a stream to receive property change notifications.
- Parameters:
property_name – the property to register for.
stream – the stream used to send events.
- Raises:
KeyError – if the requested name is not defined on this Thing.
- observe_action(action_name: str, stream: anyio.abc.ObjectSendStream)
Register a stream to receive action status change notifications.
- Parameters:
action_name – the action to register for.
stream – the stream used to send events.
- Raises:
KeyError – if the requested name is not defined on this Thing.
- class labthings_fastapi.ThingProperty(model: type, initial_value: Any = None, readonly: bool = False, observable: bool = False, description: str | None = None, title: str | None = None, getter: Callable | None = None, setter: Callable | None = None)
A property that can be accessed via the HTTP API.
By default, a ThingProperty acts like a normal variable, but functionality can be added in several ways.
Create a property that can be accessed via the HTTP API.
ThingPropertyis a descriptor that functions like a variable, optionally with notifications when it is set. It may also have a getter and setter, which work in a similar way to Python properties.ThingPropertycan behave in several different ways:If no
getterorsetteris specified, it will behave like a simple data attribute (i.e. a variable). IfobservableisTrue, it is possible to register for notifications when the value is set. In this case, aninitial_valueis required.If a
getteris specified andobservableisFalse, thegetterwill be called when the property is accessed, and its return value will be the property’s value, just like the builtinproperty. The property will be read-only both locally and via HTTP.If a
getteris specified andobservableisTrue, thegetteris used instead ofinitial_valuebut thereafter the property behaves like a variable. Thegetteris only on first access. The property may be written to locally, and whether it’s writable via HTTP depends on thereadonlyargument.If both a
getterandsetterare specified andobservableisFalse, the property behaves like a Python property, with thegetterbeing called when the property is accessed, and thesetterbeing called when the property is set. The property is read-only via HTTP ifreadonlyisTrue. It may always be written to locally.If
observableisTrueand asetteris specified, the property will behave like a variable, but will call thesetterwhen the property is set. Thesettermay perform tasks like sending the updated value to the hardware, but it is not responsible for remembering the value. The initial value is set via thegetterorinitial_value.
- Parameters:
model – The type of the property. This is optional, because it is better to use type hints (see notes on typing above).
initial_value – The initial value of the property. If this is set, the property must not have a getter, and should behave like a variable.
readonly – If True, the property cannot be set via the HTTP API.
observable – If True, the property can be observed for changes via websockets. This causes the setter to run code in the async event loop that will notify a list of subscribers each time the property is set. Currently, only websockets can be used to observe properties.
description – A description of the property, used in the API documentation. LabThings will attempt to take this from the docstring if not supplied.
title – A human-readable title for the property, used in the API documentation. Defaults to the first line of the docstring, or the name of the property.
getter – A function that gets the value of the property.
setter – A function that sets the value of the property.
- Raises:
ValueError – if the initial value or type are missing or incorrectly specified.
- model: type[pydantic.BaseModel]
- observable = False
- initial_value = None
- _description = None
- _title = None
- _setter
- _getter
- __set_name__(owner: type[labthings_fastapi.thing.Thing], name: str) None
Take note of the name to which the descriptor is assigned.
This is called when the descriptor is assigned to an attribute of a class.
- Parameters:
owner – the
Thingsubclass to which we are being attached.name – the name to which we have been assigned.
- property title
A human-readable title for the property.
- property description
A description of the property.
- __get__(obj: labthings_fastapi.thing.Thing | None, type: ThingProperty.__get__.type | None = None) Any
Return the value of the property.
If
objis none (i.e. we are getting the attribute of the class), we return the descriptor.If no getter is set, we’ll return either the initial value, or the value from the object’s __dict__, i.e. we behave like a variable.
If a getter is set, we will use it, unless the property is observable, at which point the getter is only ever used once, to set the initial value.
- Parameters:
obj – the
Thingto which we are attached.type – the class on which we are defined.
- Returns:
the value of the property (when accessed on an instance), or this descriptor if accessed as a class attribute.
- __set__(obj: labthings_fastapi.thing.Thing, value: Any) None
Set the property’s value.
- Parameters:
obj – the
Thingto which we are attached.value – the new value for the property.
- _observers_set(obj: labthings_fastapi.thing.Thing)
Return the observers of this property.
Each observer in this set will be notified when the property is changed. See
.ThingProperty.emit_changed_event- Parameters:
obj – the
Thingto which we are attached.- Returns:
the set of observers corresponding to
obj.
- emit_changed_event(obj: labthings_fastapi.thing.Thing, value: Any) None
Notify subscribers that the property has changed.
This function is run when properties are updated. It must be run from within a thread. This could be the
Invocationthread of a running action, or the property should be updated over via a client/http. It must be run from a thread as it is communicating with the event loop via anasyncioblocking portal and can cause deadlock if run in the event loop.- Parameters:
obj – the
Thingto which we are attached.value – the new property value, to be sent to observers.
- Raises:
NotConnectedToServerError – if the Thing that is calling the property update is not connected to a server with a running event loop.
- async emit_changed_event_async(obj: labthings_fastapi.thing.Thing, value: Any)
Notify subscribers that the property has changed.
This function may only be run in the
anyioevent loop. SeeThingProperty.emit_changed_event.- Parameters:
obj – the
Thingto which we are attached.value – the new property value, to be sent to observers.
- property name
The name of the property.
This should be consistent between the class definition and the Thing Description as well as appearing in the URLs for getting and setting.
- add_to_fastapi(app: fastapi.FastAPI, thing: labthings_fastapi.thing.Thing) None
Add this action to a FastAPI app, bound to a particular Thing.
- Parameters:
app – The FastAPI application we are adding endpoints to.
thing – The
Thingwe are adding the endpoints for.
- property_affordance(thing: labthings_fastapi.thing.Thing, path: str | None = None) labthings_fastapi.thing_description._model.PropertyAffordance
Represent the property in a Thing Description.
- Parameters:
- Returns:
A description of the property in Thing Description format.
- getter(func: Callable) typing_extensions.Self
Set the function that gets the property’s value.
- Parameters:
func – is the new getter function.
- Returns:
this property (to allow its use as a decorator).
- setter(func: Callable) typing_extensions.Self
Change the setter function.
ThingPropertydescriptors return the value they hold when they are accessed. However, they can run code when they are set: this decorator sets a function as that code.- Parameters:
func – is the new setter function.
- Returns:
this property (to allow its use as a decorator).
- class labthings_fastapi.ThingSetting(model: type, initial_value: Any = None, readonly: bool = False, observable: bool = False, description: str | None = None, title: str | None = None, getter: Callable | None = None, setter: Callable | None = None)
Bases:
ThingPropertyA
ThingPropertythat persists on disk.A setting can be accessed via the HTTP API and is persistent between sessions.
A
ThingSettingis aThingPropertywith extra functionality for triggering aThingto save its settings.Note: If a setting is mutated rather than assigned to, this will not trigger saving. For example: if a Thing has a setting called
dictsettingholding the dictionary{"a": 1, "b": 2}thenself.dictsetting = {"a": 2, "b": 2}would trigger saving butself.dictsetting[a] = 2would not, as the setter fordictsettingis never called.The setting otherwise acts just like a normal variable.
Create a property that can be accessed via the HTTP API.
ThingPropertyis a descriptor that functions like a variable, optionally with notifications when it is set. It may also have a getter and setter, which work in a similar way to Python properties.ThingPropertycan behave in several different ways:If no
getterorsetteris specified, it will behave like a simple data attribute (i.e. a variable). IfobservableisTrue, it is possible to register for notifications when the value is set. In this case, aninitial_valueis required.If a
getteris specified andobservableisFalse, thegetterwill be called when the property is accessed, and its return value will be the property’s value, just like the builtinproperty. The property will be read-only both locally and via HTTP.If a
getteris specified andobservableisTrue, thegetteris used instead ofinitial_valuebut thereafter the property behaves like a variable. Thegetteris only on first access. The property may be written to locally, and whether it’s writable via HTTP depends on thereadonlyargument.If both a
getterandsetterare specified andobservableisFalse, the property behaves like a Python property, with thegetterbeing called when the property is accessed, and thesetterbeing called when the property is set. The property is read-only via HTTP ifreadonlyisTrue. It may always be written to locally.If
observableisTrueand asetteris specified, the property will behave like a variable, but will call thesetterwhen the property is set. Thesettermay perform tasks like sending the updated value to the hardware, but it is not responsible for remembering the value. The initial value is set via thegetterorinitial_value.
- Parameters:
model – The type of the property. This is optional, because it is better to use type hints (see notes on typing above).
initial_value – The initial value of the property. If this is set, the property must not have a getter, and should behave like a variable.
readonly – If True, the property cannot be set via the HTTP API.
observable – If True, the property can be observed for changes via websockets. This causes the setter to run code in the async event loop that will notify a list of subscribers each time the property is set. Currently, only websockets can be used to observe properties.
description – A description of the property, used in the API documentation. LabThings will attempt to take this from the docstring if not supplied.
title – A human-readable title for the property, used in the API documentation. Defaults to the first line of the docstring, or the name of the property.
getter – A function that gets the value of the property.
setter – A function that sets the value of the property.
- Raises:
ValueError – if the initial value or type are missing or incorrectly specified.
- __set__(obj: labthings_fastapi.thing.Thing, value: Any)
Set the setting’s value.
This will cause the settings to be saved to disk.
- Parameters:
obj – the
Thingto which we are attached.value – the new value of the setting.
- set_without_emit(obj: labthings_fastapi.thing.Thing, value: Any)
Set the property’s value, but do not emit event to notify the server.
This function is not expected to be used externally. It is called during initial setup so that the setting can be set from disk before the server is fully started.
- Parameters:
obj – the
Thingto which we are attached.value – the new value of the setting.
- labthings_fastapi.thing_property(func: Callable) labthings_fastapi.descriptors.ThingProperty
Mark a method of a Thing as a LabThings Property.
This should be used as a decorator with a getter and a setter just like a standard python
propertydecorator. If extra functionality is not required in the decorator, then using theThingPropertyclass directly may allow for clearer codeProperties should always have a type annotation. This type annotation will be used in automatic documentation and also to serialise the value to JSON when it is sent over th network. This mean that the type of your property should either be JSON serialisable (i.e. simple built-in types) or a subclass of
pydantic.BaseModel.- Parameters:
func – A method to use as the getter for the new property.
- Returns:
A
ThingPropertydescriptor that works likepropertybut allows the value to be read over HTTP.
- labthings_fastapi.thing_setting(func: Callable) labthings_fastapi.descriptors.ThingSetting
Mark a method of a Thing as a LabThings Setting.
A setting is a property that is saved to disk, so it persists even when the LabThings server is restarted.
This should be used as a decorator with a getter and a setter just like a standard python property decorator. If extra functionality is not required in the decorator, then using the
ThingSettingclass directly may allow for clearer code where the property works like a variable.When creating a setting using this decorator, you must always add a setter as it is used to load the value from disk. This follows the same syntax as for
property, i.e. a second function with the same name, decorated with@my_property_name.setter.A type annotation is required, and should follow the same constraints as for :deco:`thing_property`.
If the type is a pydantic BaseModel, then the setter must also be able to accept the dictionary representation of this BaseModel as this is what will be used to set the Setting when loading from disk on starting the server.
Note
If a setting is mutated rather than set, this will not trigger saving. For example: if a Thing has a setting called
dictsettingholding the dictionary{"a": 1, "b": 2}thenself.dictsetting = {"a": 2, "b": 2}would trigger saving butself.dictsetting[a] = 2would not, as the setter fordictsettingis never called.- Parameters:
func – A method to use as the getter for the new property.
- Returns:
A
ThingSettingdescriptor that works likepropertybut allows the value to be read over HTTP and saves it to disk.
- labthings_fastapi.thing_action(func: Callable, **kwargs) labthings_fastapi.descriptors.ActionDescriptor
- labthings_fastapi.thing_action(**kwargs) Callable[[Callable], labthings_fastapi.descriptors.ActionDescriptor]
Mark a method of a
Thingas a LabThings Action.Methods decorated with :deco:`thing_action` will be available to call over HTTP as actions. See Actions for an introduction to the concept of actions.
This decorator may be used with or without arguments.
- Parameters:
func – The method to be decorated as an action.
**kwargs – Keyword arguments are passed to the constructor of
ActionDescriptor.
- Returns:
Whether used with or without arguments, the result is that the method is wrapped in an
ActionDescriptor, so it can be called as usual, but will also be exposed over HTTP.
- labthings_fastapi.fastapi_endpoint(method: labthings_fastapi.descriptors.HTTPMethod, path: str | None = None, **kwargs) Callable[[Callable], labthings_fastapi.descriptors.EndpointDescriptor]
Mark a function as a FastAPI endpoint without making it an action.
This decorator will cause a method of a
Thingto be directly added to the HTTP API, bypassing the machinery underlying Action and Property affordances. Such endpoints will not be documented in the Thing Description but may be used as the target of links. For example, this could allow a file to be downloaded from theThingat a known URL, or serve a video stream that wouldn’t be supported as aBlob.The majority of
Thingimplementations won’t need this decorator, but it is here to enable flexibility when it’s needed.This decorator always takes arguments; in particular,
methodis required. It should be used as:class DownloadThing(Thing): @fastapi_endpoint("get") def plain_text_response(self) -> str: return "example string"
This decorator is intended to work very similarly to the
fastapidecorators@app.get,@app.post, etc., with two changes:- The path is relative to the host
Thingand will default to the name of the method.
- The path is relative to the host
- The method will be called with the host
Thingas its first argument, i.e. it will be bound to the class as usua.
- The method will be called with the host
- Parameters:
method – The HTTP verb this endpoint responds to.
path – The path, relative to the host
Thingbase URL.**kwargs – Additional keyword arguments are passed to the
fastapi.FastAPI.getdecorator ifmethodisget, or to the equivalent decorator for other HTTP verbs.
- Returns:
When used as intended, the result is an
EndpointDescriptor.
- class labthings_fastapi.ThingServer(settings_folder: str | None = None)
Use FastAPI to serve
Thinginstances.The
ThingServersets up afastapi.FastAPIapplication and uses it to expose the capabilities ofThinginstances over HTTP.There are several functions of a
ThingServer:Manage where settings are stored, to allow
Thinginstances to load and save their settings from disk.Configure the server to allow cross-origin requests (required if we use a web app that is not served from the
ThingServer).Manage the threads used to run Actions.
Manage Blob input/output to allow binary data to be returned.
Allow threaded code to call functions in the event loop, by providing an
anyio.from_thread.BlockingPortal.
Initialise a LabThings server.
Setting up the
ThingServerinvolves creating the underlyingfastapi.FastAPIapp, setting its lifespan function (used to set up and shut down theThinginstances), and configuring it to allow cross-origin requests.We also create the
ActionManagerto manage Actions and theBlobManagerto manage the downloading of Blob input/output.- Parameters:
settings_folder – the location on disk where
Thingsettings will be saved.
- app
- settings_folder = './settings'
- action_manager
- blob_data_manager
- blocking_portal: anyio.from_thread.BlockingPortal | None = None
- set_cors_middleware() None
Configure the server to allow requests from other origins.
This is required to allow web applications access to the HTTP API, if they are not served from the same origin (i.e. if they are not served as part of the
ThingServer.).This is usually needed during development, and may be needed at other times depending on how you are using LabThings.
- property things: collections.abc.Mapping[str, labthings_fastapi.thing.Thing]
Return a dictionary of all the things.
- Returns:
a dictionary mapping thing paths to
Thinginstances.
- ThingInstance
- things_by_class(cls: type[ThingInstance]) Sequence[ThingInstance]
Return all Things attached to this server matching a class.
Return all instances of
clsattached to this server.- Parameters:
cls – A
Thingsubclass.- Returns:
all instances of
clsthat have been added to this server.
- thing_by_class(cls: type[ThingInstance]) ThingInstance
Return the instance of
clsattached to this server.This function calls
ThingServer.things_by_class, but asserts that there is exactly one match.- Parameters:
cls – a
Thingsubclass.- Returns:
the instance of
clsattached to this server.- Raises:
RuntimeError – if there is not exactly one matching Thing.
- add_thing(thing: labthings_fastapi.thing.Thing, path: str) None
Add a thing to the server.
- Parameters:
thing – The
Thinginstance to add to the server.path – the relative path to access the thing on the server. Must only contain alphanumeric characters, hyphens, or underscores.
- Raises:
ValueError – if
pathcontains invalid characters.
- async lifespan(app: fastapi.FastAPI) AsyncGenerator[None]
Manage set up and tear down of the server and Things.
This method is used as a lifespan function for the FastAPI app. See the lifespan page in FastAPI’s documentation.
This does two important things:
It sets up the blocking portal so background threads can run async code (this is required for events, streams, etc.).
It runs setup/teardown code for Things by calling them as context managers.
- Parameters:
app – The FastAPI application wrapped by the server.
- Yield:
no value. The FastAPI application will serve requests while this function yields.
- add_things_view_to_app()
Add an endpoint that shows the list of attached things.
- class labthings_fastapi.ThingClient(base_url: str, client: httpx.Client | None = None)
A client for a LabThings-FastAPI Thing.
Note
ThingClient must be subclassed to add actions/properties, so this class will be minimally useful on its own.
The best way to get a client for a particular Thing is currently
ThingClient.from_url, which dynamically creates a subclass with the right attributes.Create a ThingClient connected to a remote Thing.
- Parameters:
base_url – the base URL of the Thing. This should be the URL of the Thing Description document.
client – an optional
httpx.Clientobject to use for all HTTP requests. This may be afastapi.TestClientobject for testing purposes.
- server
- path
- client
- get_property(path: str) Any
Make a GET request to retrieve the value of a property.
- Parameters:
path – the URI of the
getpropertyendpoint, relative to thebase_url.- Returns:
the property’s value, as deserialised from JSON.
- set_property(path: str, value: Any)
Make a PUT request to set the value of a property.
- Parameters:
path – the URI of the
getpropertyendpoint, relative to thebase_url.value – the property’s value. Currently this must be serialisable to JSON.
- invoke_action(path: str, **kwargs)
Invoke an action on the Thing.
This method will make the initial POST request to invoke an action, then poll the resulting invocation until it completes. If successful, the action’s output will be returned directly.
While the action is running, log messages will be re-logged locally. If you have enabled logging to the console, these should be visible.
- Parameters:
path – the URI of the
invokeactionendpoint, relative to thebase_url**kwargs – Additional arguments will be combined into the JSON body of the
POSTrequest and sent as input to the action. These will be validated on the server.
- Returns:
the output value of the action.
- Raises:
RuntimeError – is raised if the action does not complete successfully.
- follow_link(response: dict, rel: str) httpx.Response
Follow a link in a response object, by its
relattribute.- Parameters:
response – is the dictionary returned by e.g.
poll_invocation.rel – picks the link to follow by matching its
relitem.
- Returns:
the response to making a
GETrequest to the link.
- classmethod from_url(thing_url: str, client: httpx.Client | None = None) typing_extensions.Self
Create a ThingClient from a URL.
This will dynamically create a subclass with properties and actions, and return an instance of that subclass pointing at the Thing URL.
- Parameters:
thing_url – The base URL of the Thing, which should also be the URL of its Thing Description.
client – is an optional
httpx.Clientobject. If not present, one will be created. This is particularly useful if you need to set HTTP options, or if you want to work with a local server object for testing purposes (seefastapi.TestClient).
- Returns:
a
ThingClientsubclass with properties and methods that match the retrieved Thing Description (see Thing).
- classmethod subclass_from_td(thing_description: dict) type[typing_extensions.Self]
Create a ThingClient subclass from a Thing Description.
Dynamically subclass
ThingClientto add properties and methods for each property and action in the Thing Description.- Parameters:
thing_description – A Thing Description as a dictionary, which will be used to construct the class.
- Returns:
a
ThingClientsubclass with the right properties and methods.
- labthings_fastapi.get_blocking_portal(obj: labthings_fastapi.thing.Thing) anyio.from_thread.BlockingPortal | None
Retrieve a blocking portal from a Thing.
See Concurrency in LabThings-FastAPI for more details.
When a
Thingis attached to aThingServerand theThingServeris started, it sets an attribute on eachThingto allow it to access ananyio.from_thread.BlockingPortal. This allows threaded code to call async code.This function retrieves the blocking portal from a
Thing.- Parameters:
obj – the
Thingon which we are looking for the portal.- Returns:
the blocking portal.