Skip to content
Snippets Groups Projects
Commit 51c185ce authored by florian's avatar florian
Browse files

ENH: Add option to wrap file properties in objects ...

parent 531bca1f
No related branches found
No related tags found
2 merge requests!89ENH: JsonSchemaExporter accepts do_not_create parameter.,!87ENH: JsonSchemaExporter accepts do_not_create parameter.
Pipeline #43774 passed
......@@ -46,6 +46,7 @@ class JsonSchemaExporter:
do_not_retrieve: List[str] = None,
no_remote: bool = False,
multiple_choice: List[str] = None,
wrap_files_in_objects: bool = False,
):
"""Set up a JsonSchemaExporter, which can then be applied on RecordTypes.
......@@ -86,6 +87,13 @@ class JsonSchemaExporter:
A list of reference Property names which shall be denoted as multiple choice properties.
This means that each option in this property may be selected at most once. This is not
implemented yet if the Property is not in ``do_not_create`` as well.
wrap_files_in_objects : bool, optional
Whether (lists of) files should be wrapped into an array of objects
that have a file property. The sole purpose of this wrapping is to
provide a workaround for a `react-jsonschema-form
bug<https://github.com/rjsf-team/react-jsonschema-form/issues/3957>`_
so only set this to True if you're using the exported schema with
react-json-form and you are experiencing the bug. Default is False.
"""
if not additional_options_for_text_props:
additional_options_for_text_props = {}
......@@ -111,6 +119,7 @@ class JsonSchemaExporter:
self._do_not_retrieve = do_not_retrieve
self._no_remote = no_remote
self._multiple_choice = multiple_choice
self._wrap_files_in_objects = wrap_files_in_objects
@staticmethod
def _make_required_list(rt: db.RecordType):
......@@ -177,7 +186,9 @@ class JsonSchemaExporter:
json_prop["type"] = "integer"
elif prop.datatype == db.DOUBLE:
json_prop["type"] = "number"
elif is_list_datatype(prop.datatype):
elif is_list_datatype(prop.datatype) and not (
self._wrap_files_in_objects and get_list_datatype(prop.datatype,
strict=True) == db.FILE):
json_prop["type"] = "array"
list_element_prop = db.Property(
name=prop.name, datatype=get_list_datatype(prop.datatype, strict=True))
......@@ -196,9 +207,39 @@ class JsonSchemaExporter:
json_prop["enum"] = values
if prop.name in self._multiple_choice:
json_prop["uniqueItems"] = True
elif prop.datatype == db.FILE:
json_prop["type"] = "string"
json_prop["format"] = "data-url"
elif prop.datatype == db.FILE or (
self._wrap_files_in_objects and
is_list_datatype(prop.datatype) and
get_list_datatype(prop.datatype, strict=True) == db.FILE
):
if self._wrap_files_in_objects:
# Workaround for react-jsonschema-form bug
# https://github.com/rjsf-team/react-jsonschema-form/issues/3957:
# Wrap all FILE references (regardless whether lists or
# scalars) in an array of objects that have a file property,
# since objects can be deleted, files can't.
json_prop["type"] = "array"
json_prop["items"] = {
"type": "object",
"title": "Next file",
# The wrapper object must wrap a file and can't be empty.
"required": ["file"],
# Wrapper objects must only contain the wrapped file.
"additionalProperties": False,
"properties": {
"file": {
"title": "Enter your file.",
"type": "string",
"format": "data-url"
}
}
}
if not is_list_datatype(prop.datatype):
# Scalar file, so the array has maximum length 1
json_prop["maxItems"] = 1
else:
json_prop["type"] = "string"
json_prop["format"] = "data-url"
else:
prop_name = prop.datatype
if isinstance(prop.datatype, db.Entity):
......@@ -434,6 +475,7 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
no_remote: bool = False,
multiple_choice: List[str] = None,
rjsf: bool = False,
wrap_files_in_objects: bool = False
) -> Union[dict, Tuple[dict, dict]]:
"""Create a jsonschema from a given RecordType that can be used, e.g., to
validate a json specifying a record of the given type.
......@@ -483,6 +525,14 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
rjsf : bool, optional
If True, uiSchema definitions for react-jsonschema-forms will be output as the second return
value. Default is False.
wrap_files_in_objects : bool, optional
Whether (lists of) files should be wrapped into an array of objects that
have a file property. The sole purpose of this wrapping is to provide a
workaround for a `react-jsonschema-form
bug<https://github.com/rjsf-team/react-jsonschema-form/issues/3957>`_ so
only set this to True if you're using the exported schema with
react-json-form and you are experiencing the bug. Default is False.
Returns
-------
......@@ -505,6 +555,7 @@ def recordtype_to_json_schema(rt: db.RecordType, additional_properties: bool = T
do_not_retrieve=do_not_retrieve,
no_remote=no_remote,
multiple_choice=multiple_choice,
wrap_files_in_objects=wrap_files_in_objects
)
return exporter.recordtype_to_json_schema(rt, rjsf=rjsf)
......
......@@ -331,10 +331,6 @@ def test_rt_with_list_props():
@patch("linkahead.execute_query", new=Mock(side_effect=_mock_execute_query))
def test_rt_with_references():
"""References and lists of references to files will come later, so test if
the errors are thrown correctly.
"""
rt = db.RecordType()
rt.add_property(name="RefProp", datatype=db.REFERENCE)
......@@ -560,6 +556,21 @@ def test_rt_with_references():
assert schema["properties"]["FileProp"]["type"] == "string"
assert schema["properties"]["FileProp"]["format"] == "data-url"
# wrap in array (cf. https://github.com/rjsf-team/react-jsonschema-form/issues/3957)
schema = rtjs(rt, wrap_files_in_objects=True)
assert schema["properties"]["FileProp"]["type"] == "array"
assert schema["properties"]["FileProp"]["maxItems"] == 1
assert "items" in schema["properties"]["FileProp"]
items = schema["properties"]["FileProp"]["items"]
assert items["type"] == "object"
assert len(items["required"]) == 1
assert "file" in items["required"]
assert items["additionalProperties"] is False
assert len(items["properties"]) == 1
assert "file" in items["properties"]
assert items["properties"]["file"]["type"] == "string"
assert items["properties"]["file"]["format"] == "data-url"
rt = db.RecordType()
rt.add_property(name="FileProp", datatype=db.LIST(db.FILE))
......@@ -568,6 +579,22 @@ def test_rt_with_references():
assert schema["properties"]["FileProp"]["items"]["type"] == "string"
assert schema["properties"]["FileProp"]["items"]["format"] == "data-url"
# wrap in array (cf. https://github.com/rjsf-team/react-jsonschema-form/issues/3957)
print(schema)
schema = rtjs(rt, wrap_files_in_objects=True)
assert schema["properties"]["FileProp"]["type"] == "array"
assert "maxItems" not in schema["properties"]["FileProp"]
assert "items" in schema["properties"]["FileProp"]
items = schema["properties"]["FileProp"]["items"]
assert items["type"] == "object"
assert len(items["required"]) == 1
assert "file" in items["required"]
assert items["additionalProperties"] is False
assert len(items["properties"]) == 1
assert "file" in items["properties"]
assert items["properties"]["file"]["type"] == "string"
assert items["properties"]["file"]["format"] == "data-url"
def test_broken():
......
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