|
39 | 39 | from fastapi import FastAPI, HTTPException, Request, Body, BackgroundTasks |
40 | 40 | from pydantic import BaseModel, create_model |
41 | 41 |
|
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 | +) |
45 | 48 | from .logs import add_thing_log_destination |
46 | 49 | from .utilities import model_to_dict, wrap_plain_types_in_rootmodel |
47 | 50 | from .invocations import InvocationModel, InvocationStatus |
@@ -591,6 +594,54 @@ def delete_invocation(id: uuid.UUID) -> None: |
591 | 594 | OwnerT = TypeVar("OwnerT", bound="Thing") |
592 | 595 |
|
593 | 596 |
|
| 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 | + |
594 | 645 | class ActionDescriptor( |
595 | 646 | BaseDescriptor[OwnerT, Callable[ActionParams, ActionReturn]], |
596 | 647 | Generic[ActionParams, ActionReturn, OwnerT], |
@@ -881,6 +932,18 @@ def action_affordance( |
881 | 932 | output=type_to_dataschema(self.output_model, title=f"{self.name}_output"), |
882 | 933 | ) |
883 | 934 |
|
| 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 | + |
884 | 947 |
|
885 | 948 | @overload |
886 | 949 | def action( |
|
0 commit comments