You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The interface to a `Thing` is defined by its interaction affordances, which are defined in the Thing Description. The `labthings-fastapi.client` library provides a `ThingClient` class to interact with a `Thing` via HTTP. This is a class with a method for each Action, and a property for each Property of the Thing. The intention is to provide a simple, pythonic interface that plays nicely with IDEs and autocompletion.
5
+
6
+
An additional goal is to provide an interface that is consistent between the server and client code: a `DirectThingClient` class is used by the `labthings-fastapi` server to call actions and properties of other `Thing`s, which means code for an action may be developed as an HTTP client, for example in a Jupyter notebook, and then moved to the server with minimal changes. Currently, there are a few differences in behaviour between local and remote `Thing`s, most notably the return types (which are usually Pydantic models on the server, and currently dictionaries generated from JSON on the client). This should be improved in the future.
7
+
8
+
Client code generation
9
+
----------------------
10
+
11
+
Currently, most clients are created using the class method `ThingClient.from_url`. This returns an instance of a dynamically-created subclass, rather than a `ThingClient` instance directly. The subclass is required in order to add methods and properties corresponding to the Thing Description sent by the server. While this is a solution that should work immediately, it does not work well with code completion or static analysis, and client objects must be introspected on-the-fly.
12
+
13
+
In the future, `labthings_fastapi` will generate custom client subclasses. These will have the methods and properties defined in a Python module, including type annotations. This will allow static analysis (e.g. with MyPy) and IDE autocompletion to work. Most packages that provide a `Thing` subclass will want to release a client package that is generated automatically in this way. The intention is to make it possible to add custom Python code to this client, for example to handle specialised return types more gracefully or add convenience methods.
One of the major challenges when controlling hardware, particularly from web frameworks, is concurrency. Most web frameworks assume resources (database connections, object storage, etc.) may be instantiated multiple times, and often initialise or destroy objects as required. In contrast, hardware can usually only be controlled from one process, and usually is initialised and shut down only once.
5
+
6
+
`labthings-fastapi` instantiates each `Thing` only once, and runs all code in a thread. More specifically, each time an action is invoked via HTTP, a new thread is created to run the action. Similarly, each time a property is read or written, a new thread is created to run the property method. This means that `Thing` code should protect important variables or resources using locks from the `threading` module, and need not worry about writing asynchronous code.
7
+
8
+
In the case of properties, the HTTP response is only returned once the `Thing` code is complete. Actions currently return a response immediately, and must be polled to determine when they have completed. This behaviour may change in the future, most likely with the introduction of a timeout to allow the client to choose between waiting for a response or polling.
9
+
10
+
Many of the functions that handle HTTP requests are asynchronous, running in an `anyio` event loop. This enables many HTTP connections to be handled at once with good efficiency. The interface between async and threaded code is provided by a "Blocking Portal" created when the LabThings server is started. A FastAPI Dependency allows the blocking portal to be obtained: while it's very unlikely more than one LabThings server will exist in one Python instance, we avoid referring to the blocking portal globally in an effort to avoid concurrency issues.
11
+
12
+
If threaded code needs to call code in the `anyio` event loop, the blocking portal dependency should be used. There are relatively few occasions when `Thing` code will need to consider this explicitly: more usually the blocking portal will be obtained by a LabThings function, for example the `MJPEGStream` class.
13
+
14
+
When one `Thing` calls the actions or properties of another `Thing`, either directly or via a `DirectThingClient`, no new threads are spawned: the action or property is run in the same thread as the caller. This mirrors the behaviour of the `ThingClient`, which blocks until the action or property is complete.
Copy file name to clipboardExpand all lines: docs/source/index.rst
+23-14Lines changed: 23 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,36 +10,43 @@ Welcome to labthings-fastapi's documentation!
10
10
:maxdepth:2
11
11
:caption:Contents:
12
12
13
-
core_concepts.rst
13
+
wot_core_concepts.rst
14
14
quickstart/quickstart.rst
15
15
dependencies/dependencies.rst
16
+
concurrency.rst
17
+
client_code.rst
16
18
17
19
apidocs/index
18
20
19
21
`labthings-fastapi` implements a Web of Things interface for laboratory hardware using Python. This is a ground-up rewrite of python-labthings_, replacing Flask 1 and Marshmallow with FastAPI and Pydantic. It is the underlying framework for v3 of the `OpenFlexure Microscope software <https://gitlab.com/openflexure/openflexure-microscope-server/>`_.
20
22
21
-
Features include:
23
+
`labthings-fastapi` aims to simplify the process of making laboratory instruments available via an HTTP API. Key features and design aims are below:
22
24
23
-
* Alignment with the `W3C Web of Things <https://www.w3.org/WoT/>`_ standard (see :doc:`core_concepts`)
25
+
* Functionality together in `Thing` subclasses, which represent units of hardware or software (see :doc:`wot_core_concepts`)
26
+
* Methods and properties of `Thing` subclasses may be added to the HTTP API and Thing Description using decorators
27
+
* Vocabulary and concepts are aligned with the `W3C Web of Things <https://www.w3.org/WoT/>`_ standard (see :doc:`wot_core_concepts`)
24
28
- Things are classes, with properties and actions defined exactly once
25
-
- Various improvements to TD generation and validation with `pydantic`
26
-
* Cleaner API
29
+
- Thing Descriptions are automatically generated, and validated with `pydantic`
30
+
- OpenAPI documentation is automatically generated by FastAPI
31
+
* We follow FastAPI_'s lead and try to use standard Python features to minimise unnecessary code
27
32
- Datatypes of action input/outputs and properties are defined with Python type hints
28
33
- Actions are defined exactly once, as a method of a `Thing` class
29
34
- Properties and actions are declared using decorators (or descriptors if that's preferred)
30
-
- Dependency injection is used to manage relationships between Things and dependency on the server
31
-
* Async HTTP handling
32
-
- Starlette (used by FastAPI) can handle requests asynchronously - potential for websockets/events (not used much yet)
33
-
- `Thing` code is still, for now, threaded. I intend to make it possible to write async things in the future, but don't intend it to become mandatory
34
-
* Smaller codebase
35
-
- FastAPI more or less completely eliminates OpenAPI generation code from our codebase
36
-
- Thing Description generation is very much simplified by the new structure (multiple Things instead of one massive Thing with many extensions)
35
+
- FastAPI_ "Dependency injection" is used to manage relationships between Things and dependency on the server
36
+
* Lifecycle and concurrency are appropriate for hardware: `Thing` code is always run in a thread, and each `Thing` is instantiated and shut down only once.
37
+
- Starlette (used by FastAPI) can handle requests asynchronously - this improves performance and enables websockets and other long-lived connections.
38
+
- `Thing` code is still, for now, threaded. In the future it may become possible to us other concurrency models in `Thing` code.
39
+
40
+
Compared to `python-labthings`_, this framework updates dependencies, shrinks the codebase, and simplifies the API.
41
+
* FastAPI more or less completely eliminates OpenAPI generation code from our codebase
42
+
* Marshmallow schemas and endpoint classes are replaced with Python type hints, eliminating double- or triple-definition of actions and their inputs/outputs.
43
+
* Thing Description generation is very much simplified by the new structure (multiple Things instead of one massive Thing with many extensions)
Copy file name to clipboardExpand all lines: docs/source/wot_core_concepts.rst
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
-
Core Concepts
2
-
=============
1
+
Web of Things Core Concepts
2
+
===========================
3
3
4
-
LabThings is rooted in the `W3C Web of Things standards <WoT>`_. Using IP networking in labs is not itself new, though perhaps under-used. However lack of proper standardisation has stiffled widespread adoption. LabThings, rather than try to introduce new competing standards, uses the architecture and terminology introduced by the W3C Web of Things. A full description of the core architecture can be found in the `Web of Things (WoT) Architecture <https://www.w3.org/TR/wot-architecture/#sec-wot-architecture>`_ document. However, a brief outline of the concepts relevant to `labthings-fastapi` is given below.
4
+
LabThings is rooted in the `W3C Web of Things standards <WoT>`_. Using IP networking in labs is not new, though perhaps under-used. However lack of proper standardisation has stiffled widespread adoption. LabThings, rather than try to introduce new competing standards, uses the architecture and terminology introduced by the W3C Web of Things. A full description of the core architecture can be found in the `Web of Things (WoT) Architecture <https://www.w3.org/TR/wot-architecture/#sec-wot-architecture>`_ document. However, a brief outline of the concepts relevant to `labthings-fastapi` is given below.
0 commit comments