labthings_fastapi.thing_description
Thing Description module.
This module supports the generation of Thing Descriptions. Currently, the top
level function lives in thing_description,
but most of the supporting code is in this submodule.
A Pydantic model implementing the Thing Description is in
thing_description._model, and this is used to generate our TDs -
using a pydantic.BaseModel helps make sure any TD errors get caught when
they are generated in Python, which makes them much easier to debug.
We also use the JSONSchema provided by W3C to validate the TDs we generate, in
thing_description.validation, as a double-check that we are standards-compliant.
Submodules
Attributes
Classes
Base for several classes describing datatypes. |
Functions
|
Return True if a JSONSchema dict is a reference. |
|
Look up a reference in a JSONSchema. |
|
Determine whether a JSON schema dict is an object. |
|
Convert an object from JSONSchema to Thing Description. |
|
Convert the anyof key to oneof. |
|
Convert the prefixitems key to items. |
|
Move additionalProperties into properties, or remove it. |
|
Check the recursion count is less than the limit. |
|
Convert a data type description from JSONSchema to Thing Description. |
|
Convert a Python type to a Thing Description DataSchema. |
Package Contents
- class labthings_fastapi.thing_description.DataSchema(/, **data: Any)
Bases:
pydantic.BaseModelBase for several classes describing datatypes.
See https://www.w3.org/TR/wot-thing-description11/#dataschema.
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.selfis explicitly positional-only to allowselfas a field name.- oneOf: list[DataSchema] | None = None
- items: DataSchema | List[DataSchema] | None = None
- properties: Mapping[str, DataSchema] | None = None
- model_config
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- labthings_fastapi.thing_description.JSONSchema
- labthings_fastapi.thing_description.is_a_reference(d: JSONSchema) bool
Return True if a JSONSchema dict is a reference.
JSON Schema references are one-element dictionaries with a single key,
$ref.pydanticsometimes breaks this rule and so we don’t check that it’s a single key.- Parameters:
d – A JSONSchema dictionary.
- Returns:
Trueif the dictionary contains$ref.
- labthings_fastapi.thing_description.look_up_reference(reference: str, d: JSONSchema) JSONSchema
Look up a reference in a JSONSchema.
JSONSchema allows references, where chunks of JSON may be reused. Thing Description does not allow references, so we need to resolve them and paste them in-line.
This function can only deal with local references, i.e. they must start with
#indicating they belong to the current file.This function first asserts the reference is local (i.e. starts with # so it’s relative to the current file), then looks up each path component in turn and returns the resolved chunk of JSON.
- Parameters:
reference – the local reference (should start with
#).d – the JSONSchema document.
- Returns:
the chunk of JSONSchema referenced by
referenceind.- Raises:
KeyError – if the reference is not found in the supplied JSONSchema.
NotImplementedError – if the reference does not start with
"#/and thus is not a local reference.
- labthings_fastapi.thing_description.is_an_object(d: JSONSchema) bool
Determine whether a JSON schema dict is an object.
- Parameters:
d – a chunk of JSONSchema describing a datatype.
- Returns:
Trueif thetypeisobject.
- labthings_fastapi.thing_description.convert_object(d: JSONSchema) JSONSchema
Convert an object from JSONSchema to Thing Description.
Convert JSONSchema objects to Thing Description datatypes.
Currently, this deletes the
additionalPropertieskeyword, which is not supported by Thing Description.- Parameters:
d – the JSONSchema object.
- Returns:
a copy of
d, withadditionalPropertiesdeleted.
- labthings_fastapi.thing_description.convert_anyof(d: JSONSchema) JSONSchema
Convert the anyof key to oneof.
JSONSchema makes a distinction between “anyof” and “oneof”, where the former means “any of these fields can be present” and the latter means “exactly one of these fields must be present”. Thing Description does not have this distinction, so we convert
anyoftooneof.- Parameters:
d – the JSONSchema object.
- Returns:
a copy of
d, withanyOfreplaced withoneOf.
- labthings_fastapi.thing_description.convert_prefixitems(d: JSONSchema) JSONSchema
Convert the prefixitems key to items.
JSONSchema 2019 (as used by thing description) used
itemswith a list of values in the same way that JSONSchema now usesprefixitems.JSONSchema 2020 uses
itemsto mean the same asadditionalItemsin JSONSchema 2019 - but Thing Description doesn’t support theadditionalItemskeyword. This will result in us overwriting additional items, and we raise a ValueError if that happens.This behaviour may be relaxed in the future.
- Parameters:
d – the JSONSchema object.
- Returns:
a copy of
d, converted to 2019 format as above.- Raises:
KeyError – if we would overwrite an existing
itemskey.
- labthings_fastapi.thing_description.convert_additionalproperties(d: JSONSchema) JSONSchema
Move additionalProperties into properties, or remove it.
JSONSchema uses
additionalPropertiesto define optional properties ofobjects. For Thing Descriptions, this should be moved inside thepropertiesobject.- Parameters:
d – the JSONSchema object.
- Returns:
a copy of
d, withadditionalPropertiesmoved intopropertiesor deleted ifpropertiesis not present.
- labthings_fastapi.thing_description.check_recursion(depth: int, limit: int) None
Check the recursion count is less than the limit.
- Parameters:
depth – the current recursion depth.
limit – the maximum recursion depth.
- Raises:
ValueError – if we exceed the recursion depth.
- labthings_fastapi.thing_description.jsonschema_to_dataschema(d: JSONSchema, root_schema: JSONSchema | None = None, recursion_depth: int = 0, recursion_limit: int = 99) JSONSchema
Convert a data type description from JSONSchema to Thing Description.
Thing Description represents datatypes with DataSchemas, which are almost but not quite JSONSchema format. There are two main tasks to convert them:
Resolving references
JSONSchema allows schemas to be replaced with
{"$ref": "#/path/to/schema"}. Thing Description does not allow this.dereference_jsonschema_dicttakes adictrepresentation of a JSON Schema document, and replaces all the references with the appropriate chunk of the file.Converting union types
JSONSchema can represent
Uniontypes using theanyOfkeyword, which is calledoneOfby Thing Description. It’s possible to achieve the same thing in the specific case of array elements, by settingitemsto a list ofDataSchemaobjects. This function does not yet do that conversion.This generates a copy of the document, to avoid messing up
pydantic’s cache.This function runs recursively: to start with, only
dshould be provided (the input JSONSchema). We will use the other arguments to keep track of recursion as we convert the schema.- param d:
a JSONSchema representation of a datatype.
- param root_schema:
the whole JSONSchema document, for resolving references. This will be set to
dwhen the function is called initially.- param recursion_depth:
how deeply this function has recursed (starts at zero).
- param recursion_limit:
how deeply this function is allowed to recurse.
- return:
the datatype in Thing Description format. This is not yet a
DataSchemainstance, but may be trivially converted to one withDataSchema(**schema).
- labthings_fastapi.thing_description.type_to_dataschema(t: type, **kwargs: Any) _model.DataSchema
Convert a Python type to a Thing Description DataSchema.
This makes use of pydantic’s
schema_offunction to create a json schema, then applies some fixes to make a DataSchema as per the Thing Description (because Thing Description is almost but not quite compatible with JSONSchema).Additional keyword arguments are added to the DataSchema, and will override the fields generated from the type that is passed in. Typically you’ll want to use this for the
titlefield.- Parameters:
t – the Python datatype or
pydantic.BaseModelsubclass.**kwargs – Additional keyword arguments passed to the
DataSchemaconstructor, often includingtitle.
- Returns:
a
DataSchemarepresenting the type.- Raises:
ValidationError – if the datatype cannot be represented by a
DataSchema.