labthings_fastapi.utilities

Utility functions used by LabThings-FastAPI.

Submodules

Classes

LabThingsObjectData

Data used by LabThings, stored on each Thing.

Functions

class_attributes(→ Iterable[tuple[str, Any]])

List all the attributes of an object's class.

attributes(→ Iterable[tuple[str, Any]])

List all the attributes of an object not starting with __.

labthings_data(→ LabThingsObjectData)

Get (or create) a dictionary for LabThings properties.

wrap_plain_types_in_rootmodel(→ type[pydantic.BaseModel])

Ensure a type is a subclass of BaseModel.

model_to_dict(→ Dict[str, Any])

Convert a pydantic model to a dictionary, non-recursively.

Package Contents

labthings_fastapi.utilities.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__.

Parameters:

obj – The instance, usually a Thing instance.

Yield:

tuples of (name, value) giving each attribute of the class.

labthings_fastapi.utilities.attributes(cls: Any) Iterable[tuple[str, Any]]

List all the attributes of an object not starting with __.

Parameters:

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.

class labthings_fastapi.utilities.LabThingsObjectData

Data used by LabThings, stored on each Thing.

This pydantic.dataclass groups together some properties used by LabThings descriptors, to avoid cluttering the namespace of the Thing subclass on which they are defined.

property_observers: Dict[str, weakref.WeakSet] = None

The observers added to each property.

Keys are property names, values are weak sets used by DataProperty.

action_observers: Dict[str, weakref.WeakSet] = None

The observers added to each action.

Keys are action names, values are weak sets used by ActionDescriptor.

labthings_fastapi.utilities.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 Thing, and return it.

Parameters:

obj – The Thing we are looking for the dataclass on.

Returns:

a LabThingsObjectData instance attached to obj.

labthings_fastapi.utilities.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.

Parameters:
  • model – A Python type or pydantic model.

  • constraints – is passed as keyword arguments to pydantic.Field to add validation constraints to the property.

Returns:

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.

  • SchemaError – if other errors prevent Pydantic from creating a schema for the generated model.

labthings_fastapi.utilities.model_to_dict(model: pydantic.BaseModel | None) 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.

Parameters:

model – A Pydantic model (usually the input of an action).

Returns:

A dictionary with string keys, which are the fields of the model. This should be suitable for using as **kwargs to an action.

Raises:

ValueError – if we are given a root model that isn’t empty.