Skip to content

Commit 2e0eb20

Browse files
authored
Merge pull request #258 from labthings/descriptor-info
Easier access to metadata and other features of properties/actions
2 parents 9ec8a20 + cf71428 commit 2e0eb20

File tree

11 files changed

+1173
-130
lines changed

11 files changed

+1173
-130
lines changed

src/labthings_fastapi/actions.py

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@
3939
from fastapi import FastAPI, HTTPException, Request, Body, BackgroundTasks
4040
from pydantic import BaseModel, create_model
4141

42-
from labthings_fastapi.middleware.url_for import URLFor
43-
44-
from .base_descriptor import BaseDescriptor
42+
from .middleware.url_for import URLFor
43+
from .base_descriptor import (
44+
BaseDescriptor,
45+
BaseDescriptorInfo,
46+
DescriptorInfoCollection,
47+
)
4548
from .logs import add_thing_log_destination
4649
from .utilities import model_to_dict, wrap_plain_types_in_rootmodel
4750
from .invocations import InvocationModel, InvocationStatus
@@ -591,6 +594,54 @@ def delete_invocation(id: uuid.UUID) -> None:
591594
OwnerT = TypeVar("OwnerT", bound="Thing")
592595

593596

597+
class ActionInfo(
598+
BaseDescriptorInfo[
599+
"ActionDescriptor", OwnerT, Callable[ActionParams, ActionReturn]
600+
],
601+
Generic[OwnerT, ActionParams, ActionReturn],
602+
):
603+
"""Convenient access to the metadata of an action."""
604+
605+
@property
606+
def response_timeout(self) -> float:
607+
"""The time to wait before replying to the HTTP request initiating an action."""
608+
return self.get_descriptor().response_timeout
609+
610+
@property
611+
def retention_time(self) -> float:
612+
"""How long to retain the action's output for, in seconds."""
613+
return self.get_descriptor().retention_time
614+
615+
@property
616+
def input_model(self) -> type[BaseModel]:
617+
"""A Pydantic model for the input parameters of an Action."""
618+
return self.get_descriptor().input_model
619+
620+
@property
621+
def output_model(self) -> type[BaseModel]:
622+
"""A Pydantic model for the output parameters of an Action."""
623+
return self.get_descriptor().output_model
624+
625+
@property
626+
def invocation_model(self) -> type[BaseModel]:
627+
"""A Pydantic model for an invocation of this action."""
628+
return self.get_descriptor().invocation_model
629+
630+
@property
631+
def func(self) -> Callable[Concatenate[OwnerT, ActionParams], ActionReturn]:
632+
"""The function that runs the action."""
633+
return self.get_descriptor().func
634+
635+
636+
class ActionCollection(
637+
DescriptorInfoCollection[OwnerT, ActionInfo],
638+
Generic[OwnerT],
639+
):
640+
"""Access to the metadata of each Action."""
641+
642+
_descriptorinfo_class = ActionInfo
643+
644+
594645
class ActionDescriptor(
595646
BaseDescriptor[OwnerT, Callable[ActionParams, ActionReturn]],
596647
Generic[ActionParams, ActionReturn, OwnerT],
@@ -881,6 +932,18 @@ def action_affordance(
881932
output=type_to_dataschema(self.output_model, title=f"{self.name}_output"),
882933
)
883934

935+
def descriptor_info(self, owner: OwnerT | None = None) -> ActionInfo:
936+
r"""Return an `.ActionInfo` object describing this action.
937+
938+
The returned object will either refer to the class, or be bound to a particular
939+
instance. If it is bound, more properties will be available - e.g. we will be
940+
able to get the bound function.
941+
942+
:param owner: The owning object, or `None` to return an unbound `.ActionInfo`\ .
943+
:return: An `.ActionInfo` object describing this Action.
944+
"""
945+
return self._descriptor_info(ActionInfo, owner)
946+
884947

885948
@overload
886949
def action(

0 commit comments

Comments
 (0)