Skip to content
Snippets Groups Projects
Verified Commit 0ea525c5 authored by Daniel Hornung's avatar Daniel Hornung
Browse files

ENH: "Do not retrieve" option for json schema exporter.

parent fbebdfd8
No related branches found
No related tags found
2 merge requests!89ENH: JsonSchemaExporter accepts do_not_create parameter.,!84F more jsonschema export
Pipeline #43235 passed
...@@ -40,6 +40,8 @@ class JsonSchemaExporter: ...@@ -40,6 +40,8 @@ class JsonSchemaExporter:
additional_options_for_text_props: dict = None, additional_options_for_text_props: dict = None,
units_in_description: bool = True, units_in_description: bool = True,
do_not_create: List[str] = None, do_not_create: List[str] = None,
do_not_retrieve: List[str] = None,
no_remote: bool = False,
): ):
"""Set up a JsonSchemaExporter, which can then be applied on RecordTypes. """Set up a JsonSchemaExporter, which can then be applied on RecordTypes.
...@@ -63,17 +65,27 @@ class JsonSchemaExporter: ...@@ -63,17 +65,27 @@ class JsonSchemaExporter:
A list of RedcordType names, for which there should be no option A list of RedcordType names, for which there should be no option
to create them. Instead, only the choice of existing elements should to create them. Instead, only the choice of existing elements should
be given. be given.
do_not_retrieve : list[str]
A list of RedcordType names, for which no Records shall be retrieved. Instead, only an
object description should be given. If this list overlaps with the `do_not_create`
parameter, the behavior is undefined.
no_remote : bool
If True, do not attempt to connect to a LinkAhead server at all. Default is False.
""" """
if not additional_options_for_text_props: if not additional_options_for_text_props:
additional_options_for_text_props = {} additional_options_for_text_props = {}
if not do_not_create: if not do_not_create:
do_not_create = [] do_not_create = []
if not do_not_retrieve:
do_not_retrieve = []
self._additional_properties = additional_properties self._additional_properties = additional_properties
self._name_and_description_in_properties = name_and_description_in_properties self._name_and_description_in_properties = name_and_description_in_properties
self._additional_options_for_text_props = additional_options_for_text_props self._additional_options_for_text_props = additional_options_for_text_props
self._units_in_description = units_in_description self._units_in_description = units_in_description
self._do_not_create = do_not_create self._do_not_create = do_not_create
self._do_not_retrieve = do_not_retrieve
self._no_remote = no_remote
@staticmethod @staticmethod
def _make_required_list(rt: db.RecordType): def _make_required_list(rt: db.RecordType):
...@@ -151,22 +163,31 @@ class JsonSchemaExporter: ...@@ -151,22 +163,31 @@ class JsonSchemaExporter:
prop_name = prop.datatype prop_name = prop.datatype
if isinstance(prop.datatype, db.Entity): if isinstance(prop.datatype, db.Entity):
prop_name = prop.datatype.name prop_name = prop.datatype.name
values = self._retrieve_enum_values(f"RECORD '{prop_name}'") if prop_name in self._do_not_retrieve:
values = []
else:
values = self._retrieve_enum_values(f"RECORD '{prop_name}'")
if prop_name in self._do_not_create: if prop_name in self._do_not_create:
# Only a simple list of values # Only a simple list of values
json_prop["enum"] = values json_prop["enum"] = values
else: else:
rt = db.execute_query(f"FIND RECORDTYPE WITH name='{prop_name}'", if self._no_remote:
unique=True) rt = prop.datatype
else:
rt = db.execute_query(f"FIND RECORDTYPE WITH name='{prop_name}'",
unique=True)
subschema = self._make_segment_from_recordtype(rt) subschema = self._make_segment_from_recordtype(rt)
subschema["title"] = "Create new" if values:
json_prop["oneOf"] = [ subschema["title"] = "Create new"
{ json_prop["oneOf"] = [
"title": "Existing entries", {
"enum": values, "title": "Existing entries",
}, "enum": values,
subschema },
] subschema
]
else:
json_prop = subschema
else: else:
raise ValueError( raise ValueError(
...@@ -203,8 +224,10 @@ class JsonSchemaExporter: ...@@ -203,8 +224,10 @@ class JsonSchemaExporter:
return prop return prop
@staticmethod def _retrieve_enum_values(self, role: str):
def _retrieve_enum_values(role: str):
if self._no_remote:
return []
possible_values = db.execute_query(f"SELECT name, id FROM {role}") possible_values = db.execute_query(f"SELECT name, id FROM {role}")
...@@ -277,7 +300,10 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T ...@@ -277,7 +300,10 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
name_and_description_in_properties: bool = False, name_and_description_in_properties: bool = False,
additional_options_for_text_props: Optional[dict] = None, additional_options_for_text_props: Optional[dict] = None,
units_in_description: bool = True, units_in_description: bool = True,
do_not_create: List[str] = None): do_not_create: List[str] = None,
do_not_retrieve: List[str] = None,
no_remote: bool = False,
):
"""Create a jsonschema from a given RecordType that can be used, e.g., to """Create a jsonschema from a given RecordType that can be used, e.g., to
validate a json specifying a record of the given type. validate a json specifying a record of the given type.
...@@ -306,6 +332,12 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T ...@@ -306,6 +332,12 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
A list of RedcordType names, for which there should be no option A list of RedcordType names, for which there should be no option
to create them. Instead, only the choice of existing elements should to create them. Instead, only the choice of existing elements should
be given. be given.
do_not_retrieve : list[str]
A list of RedcordType names, for which no Records shall be retrieved. Instead, only an
object description should be given. If this list overlaps with the `do_not_create`
parameter, the behavior is undefined.
no_remote : bool
If True, do not attempt to connect to a LinkAhead server at all. Default is False.
Returns Returns
------- -------
...@@ -320,6 +352,8 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T ...@@ -320,6 +352,8 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
additional_options_for_text_props=additional_options_for_text_props, additional_options_for_text_props=additional_options_for_text_props,
units_in_description=units_in_description, units_in_description=units_in_description,
do_not_create=do_not_create, do_not_create=do_not_create,
do_not_retrieve=do_not_retrieve,
no_remote=no_remote,
) )
return exporter.recordtype_to_json_schema(rt) return exporter.recordtype_to_json_schema(rt)
......
...@@ -27,6 +27,8 @@ import json ...@@ -27,6 +27,8 @@ import json
import linkahead as db import linkahead as db
import caosadvancedtools.json_schema_exporter as jsex import caosadvancedtools.json_schema_exporter as jsex
from collections import OrderedDict
from jsonschema import FormatChecker, validate, ValidationError from jsonschema import FormatChecker, validate, ValidationError
from pytest import raises from pytest import raises
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
...@@ -85,6 +87,8 @@ def _mock_execute_query(query_string, unique=False, **kwargs): ...@@ -85,6 +87,8 @@ def _mock_execute_query(query_string, unique=False, **kwargs):
return all_files return all_files
else: else:
print(f"Query string: {query_string}") print(f"Query string: {query_string}")
if unique is True:
return db.Entity()
return db.Container() return db.Container()
...@@ -773,3 +777,42 @@ RT5: ...@@ -773,3 +777,42 @@ RT5:
assert rt4_deep.get_parents()[0].name == "RT3" assert rt4_deep.get_parents()[0].name == "RT3"
rt5_deep = model.get_deep("RT5") rt5_deep = model.get_deep("RT5")
assert rt5_deep.get_parents()[0].name == "RT5" assert rt5_deep.get_parents()[0].name == "RT5"
@patch("linkahead.execute_query", new=Mock(side_effect=_mock_execute_query))
def test_empty_retrieve():
"""Special case: ``do_not_retrieve`` is set, or the retrieve result is empty."""
model_str = """
RT1:
description: Some text.
RT2:
obligatory_properties:
RT1:
# some_text:
# datatype: TEXT
NoRecords:
description: A RecordType without Records.
recommended_properties:
some_text:
datatype: TEXT
RT3:
obligatory_properties:
NoRecords:
"""
model = parse_model_from_string(model_str)
schema_default = rtjs(model.get_deep("RT2"))
assert "oneOf" in schema_default["properties"]["RT1"]
assert any([el.get("title") == "Existing entries" for el in
schema_default["properties"]["RT1"]["oneOf"]])
schema_noexist = rtjs(model.get_deep("RT3"))
assert schema_noexist["properties"]["NoRecords"].get("type") == "object"
schema_noexist_noremote = rtjs(model.get_deep("RT3"), no_remote=True)
assert schema_noexist_noremote["properties"]["NoRecords"].get("type") == "object"
assert (schema_noexist_noremote["properties"]["NoRecords"].get("properties")
== OrderedDict([('some_text', {'type': 'string'})]))
schema_noexist_noretrieve = rtjs(model.get_deep("RT2"), do_not_retrieve=["RT1"])
assert schema_noexist_noretrieve["properties"]["RT1"].get("type") == "object"
assert "some_date" in schema_noexist_noretrieve["properties"]["RT1"].get("properties")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment