labthings_fastapi.utilities.introspection

A collection of utility functions to analyse types and metadata.

Many parts of LabThings require us to use type annotations to generate schemas/validation/documentation. This is done using pydantic in keeping with the underlying FastAPI library.

This module collects together some utility functions that help with a few key tasks, in particular creating pydantic models from functions by analysing their signatures.

Classes

EmptyObject

A model representing an object with no required keys.

StrictEmptyObject

A model representing an object that must have no keys.

EmptyInput

Represent the input of an action that has no required parameters.

StrictEmptyInput

Represent the input of an action that never takes parameters.

Functions

input_model_from_signature(→ type[pydantic.BaseModel])

Create a pydantic model for a function's signature.

fastapi_dependency_params(→ Sequence[inspect.Parameter])

Find the arguments of a function that are FastAPI dependencies.

return_type(→ Type)

Determine the return type of a function.

get_docstring(→ Optional[str])

Return the docstring of an object.

get_summary(→ Optional[str])

Return the first line of the dosctring of an object.

Module Contents

class labthings_fastapi.utilities.introspection.EmptyObject(/, **data: Any)

Bases: pydantic.BaseModel

A model representing an object with no required keys.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class labthings_fastapi.utilities.introspection.StrictEmptyObject(/, **data: Any)

Bases: EmptyObject

A model representing an object that must have no keys.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_config

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class labthings_fastapi.utilities.introspection.EmptyInput(/, root=PydanticUndefined, **data)

Bases: pydantic.RootModel

Represent the input of an action that has no required parameters.

This may be either a dictionary or None.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

root: EmptyObject | None = None
class labthings_fastapi.utilities.introspection.StrictEmptyInput(/, root=PydanticUndefined, **data)

Bases: EmptyInput

Represent the input of an action that never takes parameters.

This may be either an empty dictionary or None.

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

root: StrictEmptyObject | None = None
labthings_fastapi.utilities.introspection.input_model_from_signature(func: Callable, remove_first_positional_arg: bool = False, ignore: Sequence[str] | None = None) type[pydantic.BaseModel]

Create a pydantic model for a function’s signature.

This is deliberately quite a lot more basic than pydantic.decorator.ValidatedFunction because it is designed to handle JSON input. That means that we don’t want positional arguments.

Note

LabThings-FastAPI does not currently support actions that take positional arguments, because this does not convert nicely into JSONSchema or Thing Description documents (see Generated documentation).

Parameters:
  • func – the function to analyse.

  • remove_first_positional_arg – Remove the first argument from the model (this is appropriate for methods, as the first argument, self, is baked in when it’s called, but is present in the signature).

  • ignore – Ignore arguments that have the specified name. This is useful for e.g. dependencies that are injected by LabThings.

Returns:

A pydantic model class describing the input parameters

Raises:
  • TypeError – if positional arguments are used: this is not supported.

  • ValueError – if remove_first_positional_arg is true but there is no initial positional argument.

labthings_fastapi.utilities.introspection.fastapi_dependency_params(func: Callable) Sequence[inspect.Parameter]

Find the arguments of a function that are FastAPI dependencies.

This allows us to “pass through” the full power of the FastAPI dependency injection system to thing actions. Any function parameter that has a type hint annotated with fastapi.Depends will be treated as a dependency, and thus be supplied automatically when it is called over HTTP. See Dependencies for an overview.

We give special treatment to dependency parameters, as they must not appear in the input model, and they must be supplied by the DirectThingClient wrapper to make the signature identical to that of the ThingClient over HTTP.

Note

Path and query parameters are ignored. These should not be used as action parameters, and will most likely raise an error when the Thing is added to FastAPI.

Parameters:

func – a function to inspect.

Returns:

a list of parameter objects that are annotated as dependencies.

labthings_fastapi.utilities.introspection.return_type(func: Callable) Type

Determine the return type of a function.

Parameters:

func – a function to inspect

Returns:

the return type of the function.

labthings_fastapi.utilities.introspection.get_docstring(obj: Any, remove_summary: bool = False) str | None

Return the docstring of an object.

Get the docstring of an object, optionally removing the initial “summary” line.

If remove_summary is True (not default), and the docstring’s second line is blank, the first two lines are removed. If the docstring follows the convention of a one-line summary, a blank line, and a description, this will get just the description.

The docstring is processed by inspect.cleandoc() to remove whitespace from the start of each line.

Parameters:
  • obj – Any Python object.

  • remove_summary – whether to remove the summary line, if present.

Returns:

The object’s docstring.

labthings_fastapi.utilities.introspection.get_summary(obj: Any) str | None

Return the first line of the dosctring of an object.

Parameters:

obj – Any Python object

Returns:

First line of object docstring, or None.