labthings_fastapi.outputs.blob
Module Contents
Classes
The interface for the data store of a Blob. |
|
A BlobData protocol for server-side use, i.e. including |
|
A BlobOutput that holds its data in memory as a :class: |
|
A BlobOutput that holds its data in a file |
|
A container for binary data that may be retrieved over HTTP |
|
A class to manage BlobData objects |
Functions
Create a BlobOutput subclass for a given media type |
|
Set context variables to allow blobs to be [de]serialised |
Data
This context variable gives access to a function that makes BlobData objects
downloadable, by assigning a URL and adding them to the
|
|
This context variable gives access to a function that makes BlobData objects
from a URL, by retrieving them from the
|
|
A dependency that enables |
API
- class labthings_fastapi.outputs.blob.BlobData
Bases:
typing_extensions.ProtocolThe interface for the data store of a Blob.
Blobobjects can represent their data in various ways. Each of those options must provide three ways to access the data, which are thecontentproperty, thesave()method, and theopen()method.This protocol defines the interface needed by any data store used by a
Blob.Objects that are used on the server will additionally need to implement the
ServerSideBlobDataprotocol, which adds aresponse()method andidproperty.
- class labthings_fastapi.outputs.blob.ServerSideBlobData
Bases:
labthings_fastapi.outputs.blob.BlobData,typing_extensions.ProtocolA BlobData protocol for server-side use, i.e. including
response()Blobobjects returned by actions must useBlobDataobjects that can be downloaded. This protocol extends that protocol to include aresponse()method that returns a FastAPI response object.See
BlobBytesorBlobFilefor concrete implementations.- id: Optional[uuid.UUID]
None
A unique identifier for this BlobData object.
The ID is set when the BlobData object is added to the BlobDataManager. It is used to retrieve the BlobData object from the manager.
- response() fastapi.responses.Response
A :class:
fastapi.Responseobject that sends binary data.
- class labthings_fastapi.outputs.blob.BlobBytes(data: bytes, media_type: str)
A BlobOutput that holds its data in memory as a :class:
bytesobject- response() fastapi.responses.Response
- class labthings_fastapi.outputs.blob.BlobFile(file_path: str, media_type: str, **kwargs)
A BlobOutput that holds its data in a file
Only the filepath is retained by default. If you are using e.g. a temporary directory, you should add the temporary directory as a property, to stop it being garbage collected.
- response() fastapi.responses.Response
- class labthings_fastapi.outputs.blob.Blob
Bases:
pydantic.BaseModelA container for binary data that may be retrieved over HTTP
See the documentation on blobs for more information on how to use this class.
A
Blobmay be created to hold data using the class methodsfrom_bytesorfrom_temporary_directory. The constructor will attempt to deserialise a Blob from a URL (see__init__method).You are strongly advised to subclass this class and specify the
media_typeattribute, as this will propagate to the auto-generated documentation.- href: str
None
The URL where the data may be retrieved. This will be
blob://localif the data is stored locally.
- description: str
‘The output from this action is not serialised to JSON, so it must be retrieved as a file. This link …’
- _data: Optional[labthings_fastapi.outputs.blob.ServerSideBlobData]
None
This object holds the data, either in memory or as a file.
If
_dataisNone, then the Blob has not been deserialised yet, and thehrefshould point to a valid address where the data may be downloaded.
- retrieve_data()
Retrieve the data from the URL
When a
Blobis created using its constructor,pydanticwill attempt to deserialise it by retrieving the data from the URL specified inhref. Currently, this must be a URL pointing to aBlobthat already exists on this server.This validator will only work if the function to resolve URLs to
BlobDataobjects has been set in the context variableurl_to_blobdata_ctx. This is done when actions are being invoked over HTTP by theBlobIOContextDepdependency.
- to_dict() Mapping[str, str]
Serialise the Blob to a dictionary and make it downloadable
When
pydanticserialises this object, it will call this method to convert it to a dictionary. There is a significant side-effect, which is that we will add the blob to theBlobDataManagerso it can be downloaded.This serialiser will only work if the function to assign URLs to
BlobDataobjects has been set in the context variableblobdata_to_url_ctx. This is done when actions are being returned over HTTP by theBlobIOContextDepdependency.
- classmethod default_media_type() str
The default media type.
Blobshould generally be subclassed to define the default media type, as this forms part of the auto-generated documentation. Using theBlobclass directly will result in a media type of*/*, which makes it unclear what format the output is in.
- property data: labthings_fastapi.outputs.blob.ServerSideBlobData
The data store for this Blob
Blobobjects may hold their data in various ways, defined by theServerSideBlobDataprotocol. This property returns the data store for thisBlob.If the
Blobhas not yet been downloaded, there may be no data held locally, in which case this function will raise aValueError.It is recommended to use the
contentproperty orsave()oropen()methods rather than accessing this property directly. Those methods will download data if required, rather than raising an error.
- property content: bytes
Return the the output as a
bytesobjectThis property may return the
bytesobject, or if we have a file it will read the file and return the contents. Client objects may use this property to download the output.This property is read-only. You should also only read it once, as no guarantees are given about cacheing - reading it many times risks reading the file from disk many times, or re-downloading an artifact.
- save(filepath: str) None
Save the output to a file.
This may remove the need to hold the output in memory.
- classmethod from_temporary_directory(folder: tempfile.TemporaryDirectory, file: str) typing_extensions.Self
Create a BlobOutput from a file in a temporary directory
The TemporaryDirectory object will persist as long as this BlobOutput does, which will prevent it from being cleaned up until the object is garbage collected.
- classmethod from_file(file: str) typing_extensions.Self
Create a BlobOutput from a regular file
The file should exist for at least as long as the BlobOutput does; this is assumed to be the case and nothing is done to ensure it’s not temporary. If you are using temporary files, consider creating your Blob with
from_temporary_directoryinstead.
- response()
“Return a suitable response for serving the output
- labthings_fastapi.outputs.blob.blob_type(media_type: str) type[labthings_fastapi.outputs.blob.Blob]
Create a BlobOutput subclass for a given media type
This convenience function may confuse static type checkers, so it is usually clearer to make a subclass instead, e.g.:
class MyImageBlob(Blob): media_type = "image/png"
- class labthings_fastapi.outputs.blob.BlobDataManager
A class to manage BlobData objects
The
BlobManageris responsible for servingBlobobjects to clients. It holds weak references: it will not retainBlobs that are no longer in use. MostBlobs will be retained by the output of an action: this holds a strong reference, and will be expired by theActionManager.- _blobs: weakref.WeakValueDictionary[uuid.UUID, labthings_fastapi.outputs.blob.ServerSideBlobData]
None
- __init__()
- add_blob(blob: labthings_fastapi.outputs.blob.ServerSideBlobData) uuid.UUID
Add a BlobOutput to the manager, generating a unique ID
- get_blob(blob_id: uuid.UUID) labthings_fastapi.outputs.blob.ServerSideBlobData
Retrieve a BlobOutput from the manager
- attach_to_app(app: fastapi.FastAPI)
Attach the BlobDataManager to a FastAPI app
- labthings_fastapi.outputs.blob.blobdata_to_url_ctx
‘(…)’
This context variable gives access to a function that makes BlobData objects downloadable, by assigning a URL and adding them to the
BlobDataManager.It is only available within a
blob_serialisation_context_managerbecause it requires access to theBlobDataManagerand theurl_forfunction from the FastAPI app.
- labthings_fastapi.outputs.blob.url_to_blobdata_ctx
‘(…)’
This context variable gives access to a function that makes BlobData objects from a URL, by retrieving them from the
BlobDataManager.It is only available within a
blob_serialisation_context_managerbecause it requires access to theBlobDataManager.
- async labthings_fastapi.outputs.blob.blob_serialisation_context_manager(request: fastapi.Request)
Set context variables to allow blobs to be [de]serialised
- labthings_fastapi.outputs.blob.BlobIOContextDep: typing_extensions.TypeAlias
None
A dependency that enables
Blobs to be serialised and deserialised.
BLOB Output Module
The BlobOutput class is used when you need to return something file-like that can’t easily (or efficiently) be converted to JSON. This is useful for returning large objects like images, especially where an existing file-type is the obvious way to handle it.
There is a dedicated documentation page on blobs that explains how to use this mechanism.
To return a file from an action, you should declare its return type as a BlobOutput
subclass, defining the
media_type attribute.
class MyImageBlob(Blob):
media_type = "image/png"
class MyThing(Thing):
@thing_action
def get_image(self) -> MyImageBlob:
# Do something to get the image data
data = self._get_image_data()
return MyImageBlob.from_bytes(data)
The action should then return an instance of that subclass, with data supplied
either as a bytes object or a file on disk. If files are used, it’s your
responsibility to ensure the file is deleted after the
Blob object is
garbage-collected. Constructing it using the class methods
from_bytes or
from_temporary_directory
will ensure this is done for you.
Bear in mind a tempfile object only holds a file descriptor and is not safe for
concurrent use, which does not work well with the HTTP API:
action outputs may be retrieved multiple times after the action has
completed, possibly concurrently. Creating a temp folder and making a file inside it
with
from_temporary_directory
is the safest way to deal with this.