labthings_fastapi.utilities =========================== .. py:module:: labthings_fastapi.utilities .. autoapi-nested-parse:: Utility functions used by LabThings-FastAPI. Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/labthings_fastapi/utilities/introspection/index Classes ------- .. autoapisummary:: labthings_fastapi.utilities.LabThingsObjectData Functions --------- .. autoapisummary:: labthings_fastapi.utilities.class_attributes labthings_fastapi.utilities.attributes labthings_fastapi.utilities.labthings_data labthings_fastapi.utilities.wrap_plain_types_in_rootmodel labthings_fastapi.utilities.model_to_dict Package Contents ---------------- .. py:function:: class_attributes(obj: Any) -> Iterable[tuple[str, Any]] List all the attributes of an object's class. This function gets all class attributes, including inherited ones. It is used to obtain the various descriptors used to represent properties and actions. It calls `.attributes` on ``obj.__class__``. :param obj: The instance, usually a `~lt.Thing` instance. :yield: tuples of ``(name, value)`` giving each attribute of the class. .. py:function:: attributes(cls: Any) -> Iterable[tuple[str, Any]] List all the attributes of an object not starting with `__`. :param cls: The object whose attributes we are listing. This may be a class, because classes are objects too. :yield: tuples of ``(name, value)`` giving each attribute and its value. .. py:class:: LabThingsObjectData Data used by LabThings, stored on each `~lt.Thing`. This `pydantic.dataclass` groups together some properties used by LabThings descriptors, to avoid cluttering the namespace of the `~lt.Thing` subclass on which they are defined. .. py:attribute:: property_observers :type: Dict[str, weakref.WeakSet] :value: None The observers added to each property. Keys are property names, values are weak sets used by `~lt.DataProperty`\ . .. py:attribute:: action_observers :type: Dict[str, weakref.WeakSet] :value: None The observers added to each action. Keys are action names, values are weak sets used by `.ActionDescriptor`\ . .. py:function:: labthings_data(obj: labthings_fastapi.thing.Thing) -> LabThingsObjectData Get (or create) a dictionary for LabThings properties. Ensure there is a `.LabThingsObjectData` dataclass attached to a particular `~lt.Thing`, and return it. :param obj: The `~lt.Thing` we are looking for the dataclass on. :return: a `.LabThingsObjectData` instance attached to ``obj``. .. py:function:: wrap_plain_types_in_rootmodel(model: type, constraints: collections.abc.Mapping[str, Any] | None = None) -> type[pydantic.BaseModel] Ensure a type is a subclass of BaseModel. If a `pydantic.BaseModel` subclass is passed to this function, we will pass it through unchanged. Otherwise, we wrap the type in a `pydantic.RootModel`. In the future, we may explicitly check that the argument is a type and not a model instance. :param model: A Python type or `pydantic` model. :param constraints: is passed as keyword arguments to `pydantic.Field` to add validation constraints to the property. :return: A `pydantic` model, wrapping Python types in a ``RootModel`` if needed. :raises UnsupportedConstraintError: if constraints are provided for an unsuitable type, for example `allow_inf_nan` for an `int` property, or any constraints for a `BaseModel` subclass. :raises RuntimeError: if other errors prevent Pydantic from creating a schema for the generated model. .. py:function:: model_to_dict(model: Optional[pydantic.BaseModel]) -> Dict[str, Any] Convert a pydantic model to a dictionary, non-recursively. We convert only the top level model, i.e. we do not recurse into submodels. This is important to avoid serialising Blob objects in action inputs. This function returns `dict(model)`, with exceptions for the case of `None` (converted to an empty dictionary) and `pydantic.RootModel` (checked to see if they correspond to empty input). If `pydantic.RootModel` with non-empty input is allowed, this function will need to be updated to handle them. :param model: A Pydantic model (usually the input of an action). :return: A dictionary with string keys, which are the fields of the model. This should be suitable for using as ``**kwargs`` to an action. :raise ValueError: if we are given a root model that isn't empty.