labthings_fastapi.utilities

Utility functions used by LabThings-FastAPI.

Submodules

Classes

RootModelWrapper

A RootModel subclass for automatically-wrapped types.

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

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.RootModelWrapper

Bases: pydantic.RootModel[WrappedT], Generic[WrappedT]

A RootModel subclass for automatically-wrapped types.

There are several places where LabThings needs a model, but may only have a plain Python type. This subclass indicates to LabThings that a type has been automatically wrapped, and will need to be unwrapped in order for the value to have the correct type.

It also provides methods to automatically wrap types if they are not already pydantic.BaseModel subclasses, and to unwrap them again.

classmethod wrap_type(model: type, constraints: collections.abc.Mapping[str, Any] | None = None, name: str | 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.

  • name – the name to use for the dynamically created model.

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.

  • UnserialisableTypeError – if the type being wrapped is not able to be serialised by pydantic.

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

classmethod unwrap(value: pydantic.BaseModel | None) Any

If the supplied value is a RootModelWrapper, unwrap it.

Parameters:

value – a model instance.

Returns:

the root value, if value is a RootModelWrapper, or value if not.

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.