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
Copy file name to clipboardExpand all lines: docs/source/concurrency.rst
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,3 +22,11 @@ Calling Things from other Things
22
22
23
23
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. See :doc:`using_things` for more details on how to call actions and properties of other Things.
24
24
25
+
Invocations and concurrency
26
+
---------------------------
27
+
28
+
Each time an action is run ("invoked" in :ref:`wot_cc`), we create a new thread to run it. This thread has a context variable set, such that ``lt.cancellable_sleep`` and ``lt.get_invocation_logger`` are aware of which invocation is currently running. If an action spawns a new thread (e.g. using `threading.Thread`\ ), this new thread will not have an invocation ID, and consequently the two invocation-specific functions mentioned will not work.
29
+
30
+
Usually, the best solution to this problem is to generate a new invocation ID for the thread. This means only the original action thread will receive cancellation events, and only the original action thread will log to the invocation logger. If the action is cancelled, you must cancel the background thread. This is the behaviour of `.ThreadWithInvocationID`\ .
31
+
32
+
It is also possible to copy the current invocation ID to a new thread. This is often a bad idea, as it's ill-defined whether the exception will arise in the original thread or the new one if the invocation is cancelled. Logs from the two threads will also be interleaved. If it's desirable to log from the background thread, the invocation logger may safely be passed as an argument, rather than accessed via ``lt.get_invocation_logger``\ .
Copy file name to clipboardExpand all lines: docs/source/dependencies/dependencies.rst
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ Dependencies
5
5
6
6
.. warning::
7
7
8
-
The use of dependencies is now deprecated. See :ref:`thing_connections` and `.ThingServerInterface` for a more intuitive way to access that functionality.
8
+
The use of dependencies is now deprecated. See :ref:`thing_slots` and `.ThingServerInterface` for a more intuitive way to access that functionality.
9
9
10
10
LabThings makes use of the powerful "dependency injection" mechanism in FastAPI. You can see the `FastAPI documentation`_ for more information. In brief, FastAPI dependencies are annotated types that instruct FastAPI to supply certain function arguments automatically. This removes the need to set up resources at the start of a function, and ensures everything the function needs is declared and typed clearly. The most common use for dependencies in LabThings is where an action needs to make use of another `.Thing` on the same `.ThingServer`.
11
11
@@ -14,7 +14,7 @@ Inter-Thing dependencies
14
14
15
15
.. warning::
16
16
17
-
These dependencies are deprecated - see :ref:`thing_connections` instead.
17
+
These dependencies are deprecated - see :ref:`thing_slots` instead.
18
18
19
19
Simple actions depend only on their input parameters and the `.Thing` on which they are defined. However, it's quite common to need something else, for example accessing another `.Thing` instance on the same LabThings server. There are two important principles to bear in mind here:
Copy file name to clipboardExpand all lines: docs/source/index.rst
+15-20Lines changed: 15 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,11 +7,11 @@ Documentation for LabThings-FastAPI
7
7
8
8
quickstart/quickstart.rst
9
9
wot_core_concepts.rst
10
-
lt_core_concepts.rst
10
+
structure.rst
11
11
tutorial/index.rst
12
12
examples.rst
13
13
actions.rst
14
-
thing_connections.rst
14
+
thing_slots.rst
15
15
dependencies/dependencies.rst
16
16
blobs.rst
17
17
concurrency.rst
@@ -20,26 +20,21 @@ Documentation for LabThings-FastAPI
20
20
21
21
autoapi/index
22
22
23
-
`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/>`_.
23
+
`labthings-fastapi` is a Python library to simplify the process of making laboratory instruments available via a HTTP. It aims to create an API that is usable from any modern programming language, with API documentation in both :ref:`openapi` and :ref:`gen_td` formats. It is the underlying framework for v3 of the `OpenFlexure Microscope software <https://gitlab.com/openflexure/openflexure-microscope-server/>`_. Key features and design aims are:
24
24
25
-
`labthings-fastapi` aims to simplify the process of making laboratory instruments available via an HTTP API. Key features and design aims are below:
26
-
27
-
* Functionality together in `Thing` subclasses, which represent units of hardware or software (see :doc:`wot_core_concepts`)
28
-
* Methods and properties of `Thing` subclasses may be added to the HTTP API and Thing Description using decorators
25
+
* The functionality of a unit of hardware or software is described using `.Thing` subclasses.
26
+
* Methods and properties of `.Thing` subclasses may be added to the HTTP API and associated documentation using decorators.
27
+
* Datatypes of action input/outputs and properties are defined with Python type hints.
28
+
* Actions are decorated methods of a `.Thing` class. There is no need for separate schemas or endpoint definitions.
29
+
* Properties are defined either as typed attributes (similar to `pydantic` or `dataclasses`) or with a `property`\ -like decorator.
30
+
* Lifecycle and concurrency are appropriate for hardware: `Thing` code is always run in a thread, and each `Thing` is instantiated, started up, and shut down only once.
29
31
* Vocabulary and concepts are aligned with the `W3C Web of Things <https://www.w3.org/WoT/>`_ standard (see :doc:`wot_core_concepts`)
30
-
- Things are classes, with properties and actions defined exactly once
31
-
- Thing Descriptions are automatically generated, and validated with `pydantic`
32
-
- OpenAPI documentation is automatically generated by FastAPI
33
-
* We follow FastAPI_'s lead and try to use standard Python features to minimise unnecessary code
34
-
- Datatypes of action input/outputs and properties are defined with Python type hints
35
-
- Actions are defined exactly once, as a method of a `Thing` class
36
-
- Properties and actions are declared using decorators (or descriptors if that's preferred)
37
-
- FastAPI_ "Dependency injection" is used to manage relationships between Things and dependency on the server
38
-
* 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.
39
-
- Starlette (used by FastAPI) can handle requests asynchronously - this improves performance and enables websockets and other long-lived connections.
40
-
- `Thing` code is still, for now, threaded. In the future it may become possible to us other concurrency models in `Thing` code.
41
-
42
-
Compared to `python-labthings`_, this framework updates dependencies, shrinks the codebase, and simplifies the API (see :doc:`lt_core_concepts`).
32
+
33
+
Previous version
34
+
----------------
35
+
36
+
This is a ground-up rewrite of python-labthings_, replacing Flask 1 and Marshmallow with FastAPI and Pydantic.
37
+
Compared to `python-labthings`_, this framework updates dependencies, shrinks the codebase, and simplifies the API (see :doc:`lt_structure`).
43
38
* FastAPI more or less completely eliminates OpenAPI generation code from our codebase
44
39
* Marshmallow schemas and endpoint classes are replaced with Python type hints, eliminating double- or triple-definition of actions and their inputs/outputs.
45
40
* Thing Description generation is very much simplified by the new structure (multiple Things instead of one massive Thing with many extensions)
LabThings is intended to simplify the process of making a piece of hardware available through an HTTP API and documenting that API with :ref:`gen_docs`\ .
8
+
9
+
Server
10
+
------
11
+
12
+
LabThings is a server-based framework.
13
+
The `.ThingServer` creates and manages the `.Thing` instances that represent individual hardware or software units. The functionality of those `.Thing`\ s is accessed via HTTP requests, which can be made from a web browser, the command line, or any programming language with an HTTP library.
14
+
15
+
LabThings-FastAPI is built on top of `fastapi`\ , which is a fast, modern HTTP framework. LabThings provides functionality to manage `.Thing`\ s and their actions, including:
16
+
17
+
* Initialising, starting up, and shutting down the `.Thing` instances, so that hardware is correctly started up and shut down.
18
+
* Managing actions, including making logs and output values available over HTTP.
19
+
* Managing `.Blob` input and output (i.e. binary objects that are best not serialised to JSON).
20
+
* Generating a :ref:`gen_td` in addition to the :ref:`openapi` documentation produced by `fastapi`\ .
21
+
* Making connections between `.Thing` instances as required.
22
+
23
+
`.Thing`\ s
24
+
-----------
25
+
26
+
Each unit of hardware (or software) that should be exposed by the server is implemented as a subclass of `.Thing`\ . A `.Thing` subclass represents a particular type of instrument (whether hardware or software), and its functionality is described using actions and properties, described below. `.Thing`\ s don't have to correspond to separate pieces of hardware: it's possible (and indeed recommended) to use `.Thing` subclasses for software components, plug-ins, swappable modules, or anything else that needs to add functionality to the server. `.Thing`\ s may access each other's attributes, so you can write a `.Thing` that implements a particular measurement protocol or task, using hardware that's accessed through other `.Thing` instances on the server. Each `.Thing` is documented by a :ref:`gen_td` which outlines its features in a higher-level way than :ref:`openapi`\ .
27
+
28
+
The attributes of a `.Thing` are made available over HTTP by decorating or marking them with the following functions:
29
+
30
+
* `.property` may be used as a decorator analogous to Python's built-in ``@property``\ . It can also be used to mark class attributes as variables that should be available over HTTP.
31
+
* `.setting` works similarly to `.property` but it is persisted to disk when the server stops, so the value is remembered.
32
+
* `.thing_action` is a decorator that makes methods available over HTTP.
33
+
* `.thing_slot` tells LabThings to supply an instance of another `.Thing` at runtime, so your `.Thing` can make use of it.
34
+
35
+
Client Code
36
+
-----------
37
+
38
+
Client code can be written in any language that supports an HTTP request. However, LabThings FastAPI provides additional functionality that makes writing client code in Python easier.
39
+
40
+
`.ThingClient` is a class that wraps up the required HTTP requests into a simpler interface. It can retrieve the :ref:`gen_td` over HTTP and use it to generate a new object with methods matching each `.thing_action` and properties matching each `.property`.
41
+
42
+
While the current dynamic implementation of `.ThingClient` can be inspected with functions like `help` at runtime, it does not work well with static tools like `mypy` or `pyright`\ . In the future, LabThings should be able to generate static client code that works better with autocompletion and type checking.
0 commit comments