labthings_fastapi.actions ========================= .. py:module:: labthings_fastapi.actions .. autoapi-nested-parse:: Actions module. :ref:`actions` are represented by methods, decorated with the `lt.action` decorator. See the :ref:`actions` documentation for a top-level overview of actions in LabThings-FastAPI. Developer notes --------------- Currently much of the code related to Actions is in `lt.action` and the underlying `.ActionDescriptor`. This is likely to be refactored in the near future. Classes ------- .. autoapisummary:: labthings_fastapi.actions.Invocation labthings_fastapi.actions.ActionManager Module Contents --------------- .. py:class:: Invocation(action: ActionDescriptor, thing: labthings_fastapi.thing.Thing, id: uuid.UUID, input: Optional[pydantic.BaseModel] = None, dependencies: Optional[dict[str, Any]] = None, log_len: int = 1000) Bases: :py:obj:`threading.Thread` A Thread subclass that retains output values and tracks progress. `.Invocation` threads add several bits of functionality compared to the base `threading.Thread`. * They are instantiated with an `.ActionDescriptor` and a `~lt.Thing` rather than a target function (see ``__init__``). * Each invocation is assigned a unique ``ID`` to allow it to be polled over HTTP. * A `.CancelHook` is provided to allow the invocation to stop gracefully if it is cancelled by the user. Create a thread to run an action and track its outputs. :param action: provides the function that we run, as well as metadata and type information. The descriptor is not bound to an object, so we supply the `~lt.Thing` it's bound to when the function is run. :param thing: is the object on which we are running the ``action``, i.e. it is supplied to the function wrapped by ``action`` as the ``self`` argument. :param id: is a `uuid.UUID` used to identify the invocation, for example when polling its status via HTTP. :param input: is a `pydantic.BaseModel` representing the body of the HTTP request that invoked the action. It is supplied to the function as keyword arguments. :param dependencies: is a dictionary of keyword arguments, supplied by FastAPI by its dependency injection mechanism. :param log_len: sets the number of log entries that will be held in memory by the invocation's logger. .. py:attribute:: action_ref .. py:attribute:: thing_ref .. py:attribute:: input .. py:attribute:: dependencies .. py:attribute:: _ID .. py:attribute:: retention_time .. py:attribute:: expiry_time :type: Optional[datetime.datetime] :value: None .. py:attribute:: _status_lock .. py:attribute:: _status :type: labthings_fastapi.invocations.InvocationStatus .. py:attribute:: _return_value :type: Optional[Any] :value: None .. py:attribute:: _request_time :type: datetime.datetime .. py:attribute:: _start_time :type: Optional[datetime.datetime] :value: None .. py:attribute:: _end_time :type: Optional[datetime.datetime] :value: None .. py:attribute:: _exception :type: Optional[Exception] :value: None .. py:attribute:: _log :type: collections.deque .. py:property:: id :type: uuid.UUID UUID for the thread. Note this not the same as the native thread ident. .. py:property:: output :type: Any Return value of the Action. If the Action is still running, returns None. .. py:property:: log :type: list[logging.LogRecord] A list of log items generated by the Action. .. py:property:: status :type: labthings_fastapi.invocations.InvocationStatus Current running status of the thread. See `.InvocationStatus` for the values and their meanings. .. py:property:: thing :type: labthings_fastapi.thing.Thing The `~lt.Thing` to which the action is bound, i.e. this is ``self``. :raises RuntimeError: if the Thing no longer exists. .. py:property:: cancel_hook :type: labthings_fastapi.invocation_contexts.CancelEvent The cancel event associated with this Invocation. .. py:method:: cancel() -> None Cancel the task by requesting the code to stop. This is an opt-in feature: the action must use a `.CancelHook` dependency and periodically check it. .. py:method:: response() -> labthings_fastapi.invocations.InvocationModel Generate a representation of the invocation suitable for HTTP. When an invocation is polled, we return a JSON object that includes its status, any log entries, a return value (if completed), and a link to poll for updates. :return: an `.InvocationModel` representing this `.Invocation`. .. py:method:: run() -> None Run the action and track progress. `.Invocation` overrides the default `threading.Thread.run` method to add ways to track its progress and capture the return value. The code to be run is the function wrapped in the `.ActionDescriptor` that is passed in as ``action``. Its arguments are the associated `~lt.Thing` (the first argument, i.e. ``self``), the ``input`` model (split into keyword arguments for each field), and any ``dependencies`` (also as keyword arguments). We update the status of the action by setting ``self._status`` and emitting a changed event. This runs async code in the event loop that informs any clients listening over websockets that the event's status has changed. Logs are retained by a custom log handler, and are included when the `.Invocation` is serialised over HTTP. If exceptions are raised by the action code, these are caught and stored. The status is then set to ERROR and the thread terminates. See `.Invocation.status` for status values. :raises RuntimeError: if there is no Thing associated with the invocation. .. py:class:: ActionManager A class to manage a collection of actions. Set up an `.ActionManager`. .. py:attribute:: _invocations :type: dict[uuid.UUID, Invocation] .. py:attribute:: _invocations_lock .. py:property:: invocations :type: list[Invocation] A list of all the `.Invocation` objects running or recently completed. .. py:method:: append_invocation(invocation: Invocation) -> None Add an `.Invocation` to the `.ActionManager`. :param invocation: The `.Invocation` to add. .. py:method:: invoke_action(action: ActionDescriptor, thing: labthings_fastapi.thing.Thing, input: Any, dependencies: dict[str, Any]) -> Invocation Invoke an action, returning the thread where it's running. See `.Invocation` for more details. :param action: provides the function that we run, as well as metadata and type information. The descriptor is not bound to an object, so we supply the `~lt.Thing` it's bound to when the function is run. :param thing: is the object on which we are running the ``action``, i.e. it is supplied to the function wrapped by ``action`` as the ``self`` argument. :param input: is a `pydantic.BaseModel` representing the body of the HTTP request that invoked the action. It is supplied to the function as keyword arguments. :param dependencies: is a dictionary of keyword arguments, supplied by FastAPI by its dependency injection mechanism. :return: an `.Invocation` object that has been started. .. py:method:: get_invocation(id: uuid.UUID) -> Invocation Retrieve an invocation by ID. :param id: the unique ID of the action to retrieve. :return: the `.Invocation` object. .. py:method:: list_invocations(action: Optional[ActionDescriptor] = None, thing: Optional[labthings_fastapi.thing.Thing] = None, request: Optional[fastapi.Request] = None) -> list[labthings_fastapi.invocations.InvocationModel] All of the invocations currently managed. Returns a list of `.InvocationModel` instances representing all the invocations that are currently running, or have recently completed and not yet expired. :param action: filters out only the invocations of a particular `.ActionDescriptor`. Note that if there are two Things of the same subclass, filtering by action will return invocations on either `~lt.Thing`. :param thing: returns only invocations of actions on a particular `~lt.Thing`. This will often be combined with filtering by ``action`` to give the list of invocations returned by a GET request on an action endpoint. :param request: is used to pass a `fastapi.Request` object to the `.Invocation.response` method. Doing so ensures the URL returned as ``href`` in the response matches the address used to communicate with the server (i.e. it uses `fastapi.Request.url_for` instead of a path generated from a string). :return: A list of invocations, optionally filtered by Thing and/or Action. .. py:method:: expire_invocations() -> None Delete invocations that have passed their expiry time. .. py:method:: router() -> fastapi.APIRouter Create a FastAPI Router with action-related endpoints. :return: a Router with all action-related endpoints.