Skip to content

Commit 3625f28

Browse files
committed
Move blobs to BlobManager
Blob URLs now start with `blob/` and are easier to generate. Blob objects are `BaseModel` subclasses that can be serialised/deserialised, using contextvars to generate URLs and retrieve BlobData objects. This obviates file responses from invocation outputs and also the `invocations/<id>/files` endpoint
1 parent ac8307c commit 3625f28

File tree

6 files changed

+239
-226
lines changed

6 files changed

+239
-226
lines changed

src/labthings_fastapi/actions/__init__.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import weakref
1010
from fastapi import FastAPI, HTTPException, Request
1111
from fastapi.responses import FileResponse
12-
from pydantic import BaseModel, RootModel
12+
from pydantic import BaseModel
1313

1414
from labthings_fastapi.utilities import model_to_dict
1515
from labthings_fastapi.utilities.introspection import EmptyInput
@@ -176,16 +176,6 @@ def run(self):
176176

177177
action = self.action
178178
thing = self.thing
179-
#kwargs = self.input.model_dump() or {}
180-
# if isinstance(self.input, RootModel):
181-
# if self.input.root is not None:
182-
# print(f"confused by {self.input}")
183-
# raise ValueError("RootModel inputs are only used for None")
184-
# kwargs = {}
185-
# elif isinstance(self.input, BaseModel):
186-
# kwargs = dict(self.input)
187-
# else:
188-
# kwargs = {}
189179
kwargs = model_to_dict(self.input)
190180
assert action is not None
191181
assert thing is not None
@@ -338,7 +328,9 @@ def list_all_invocations(request: Request, _blob_manager: BlobIOContextDep):
338328
response_model=InvocationModel,
339329
responses={404: {"description": "Invocation ID not found"}},
340330
)
341-
def action_invocation(id: uuid.UUID, request: Request, _blob_manager: BlobIOContextDep):
331+
def action_invocation(
332+
id: uuid.UUID, request: Request, _blob_manager: BlobIOContextDep
333+
):
342334
try:
343335
with self._invocations_lock:
344336
return self._invocations[id].response(request=request)

src/labthings_fastapi/descriptors/action.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
input_model_from_signature,
2121
return_type,
2222
)
23-
from ..outputs.blob import blob_to_model, get_model_media_type
23+
from ..outputs.blob import BlobIOContextDep
2424
from ..thing_description import type_to_dataschema
2525
from ..thing_description.model import ActionAffordance, ActionOp, Form, Union
2626

@@ -70,7 +70,7 @@ def __init__(
7070
remove_first_positional_arg=True,
7171
ignore=[p.name for p in self.dependency_params],
7272
)
73-
self.output_model = blob_to_model(return_type(func))
73+
self.output_model = return_type(func)
7474
self.invocation_model = create_model(
7575
f"{self.name}_invocation",
7676
__base__=InvocationModel,
@@ -165,6 +165,7 @@ def add_to_fastapi(self, app: FastAPI, thing: Thing):
165165
# the function to the decorator.
166166
def start_action(
167167
action_manager: ActionManagerContextDep,
168+
_blob_manager: BlobIOContextDep,
168169
request: Request,
169170
body,
170171
id: InvocationID,
@@ -221,8 +222,8 @@ def start_action(
221222
except AttributeError:
222223
print(f"Failed to generate response model for action {self.name}")
223224
# Add an additional media type if we may return a file
224-
if get_model_media_type(self.output_model):
225-
responses[200]["content"][get_model_media_type(self.output_model)] = {}
225+
if hasattr(self.output_model, "media_type"):
226+
responses[200]["content"][self.output_model.media_type] = {}
226227
# Now we can add the endpoint to the app.
227228
app.post(
228229
thing.path + self.name,

0 commit comments

Comments
 (0)