Skip to content
Snippets Groups Projects

ENH: JsonSchemaExporter can merge schemata and arrayize them

Merged Daniel Hornung requested to merge f-more-jsonschema-export into dev
@@ -20,9 +20,12 @@
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
"""Module for converting a data model into a json schema compatible dictionary.
The scope of this json schema is the automatic generation of user interfaces.
"""
from typing import Any, List, Optional
from collections import OrderedDict
from typing import Any, Dict, Iterable, List, Optional, Union
import linkahead as db
from linkahead.common.datatype import get_list_datatype, is_list_datatype
@@ -46,8 +49,8 @@ class JsonSchemaExporter:
Whether additional properties will be admitted in the resulting
schema. Optional, default is True.
name_and_description_in_properties : bool, optional
Whether to include name and description in the `properties` section of
the schema to be exported. Optional, default is False.
Whether objects that are generated from reference properties shall have a `name` and
`description` property in the generated schema. Optional, default is False.
additional_options_for_text_props : dict, optional
Dictionary containing additional "pattern" or "format" options for
string-typed properties. Optional, default is empty.
@@ -113,7 +116,7 @@ class JsonSchemaExporter:
return self._make_text_property(prop.description, text_format, text_pattern)
json_prop = {}
json_prop = OrderedDict()
if prop.description:
json_prop["description"] = prop.description
if self._units_in_description and prop.unit:
@@ -142,8 +145,8 @@ class JsonSchemaExporter:
values = self._retrieve_enum_values("RECORD") + self._retrieve_enum_values("FILE")
json_prop["enum"] = values
elif prop.datatype == db.FILE:
# TODO: different issue
raise NotImplementedError("Files have not been implemented yet.")
json_prop["type"] = "string"
json_prop["format"] = "data-url"
else:
prop_name = prop.datatype
if isinstance(prop.datatype, db.Entity):
@@ -224,7 +227,7 @@ class JsonSchemaExporter:
schema["required"] = self._make_required_list(rt)
schema["additionalProperties"] = self._additional_properties
props = {}
props = OrderedDict()
if self._name_and_description_in_properties:
props["name"] = self._make_text_property("The name of the Record to be created")
props["description"] = self._make_text_property(
@@ -257,7 +260,9 @@ class JsonSchemaExporter:
schema : dict
A dict containing the json schema created from the given RecordType's properties.
"""
if rt is None:
raise ValueError(
"recordtype_to_json_schema(...) cannot be called with a `None` RecordType.")
schema = self._make_segment_from_recordtype(rt)
schema["$schema"] = "https://json-schema.org/draft/2019-09/schema"
if rt.name:
@@ -287,8 +292,8 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
Whether additional properties will be admitted in the resulting
schema. Optional, default is True.
name_and_description_in_properties : bool, optional
Whether to include name and description in the `properties` section of
the schema to be exported. Optional, default is False.
Whether objects that are generated from reference properties shall have a `name` and
`description` property in the generated schema. Optional, default is False.
additional_options_for_text_props : dict, optional
Dictionary containing additional "pattern" or "format" options for
string-typed properties. Optional, default is empty.
@@ -317,3 +322,93 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
do_not_create=do_not_create,
)
return exporter.recordtype_to_json_schema(rt)
def make_array(schema: dict) -> dict:
"""Create an array of the given schema.
The result will look like this:
.. code:: js
{ "type": "array",
"items": {
// the schema
}
}
Parameters
----------
schema : dict
The JSON schema which shall be packed into an array.
Returns
-------
out : dict
A JSON schema dict with a top-level array which contains instances of the given schema.
"""
result = {
"type": "array",
"items": schema,
"$schema": "https://json-schema.org/draft/2019-09/schema",
}
return result
def merge_schemas(schemas: Union[Dict[str, dict], Iterable[dict]]) -> dict:
"""Merge the given schemata into a single schema.
The result will look like this:
.. code:: js
{
"type": "object",
"properties": {
// A, B, C
},
"required": [
// "A", "B", "C"
],
"additionalProperties": false
}
Parameters
----------
schemas : dict[str, dict] | Iterable[dict]
A dict or iterable of schemata which shall be merged together. If this is a dict, the keys will
be used as property names, otherwise the titles of the submitted schemata. If they have no title,
numbers will be used as a fallback. Note that even with a dict, the original schema's "title" is
not changed.
Returns
-------
out : dict
A JSON schema dict with a top-level object which contains the given schemata as properties.
"""
sub_schemas: dict[str, dict] = OrderedDict()
required = []
if isinstance(schemas, dict):
sub_schemas = schemas
required = [str(k) for k in schemas.keys()]
else:
for i, schema in enumerate(schemas, start=1):
title = schema.get("title", str(i))
sub_schemas[title] = schema
required.append(title)
result = {
"type": "object",
"properties": sub_schemas,
"required": required,
"additionalProperties": False,
"$schema": "https://json-schema.org/draft/2019-09/schema",
}
return result
Loading