diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py index ec45dec070d1ea731648fe8d45e44ba89e393f76..80a6ee11e707fb3776fc96b42a16b649ac575f66 100644 --- a/src/caosdb/common/models.py +++ b/src/caosdb/common/models.py @@ -55,6 +55,7 @@ from caosdb.exceptions import (AmbiguousEntityError, AuthorizationError, EntityDoesNotExistError, EntityError, EntityHasNoDatatypeError, HTTPURITooLongError, MismatchingEntitiesError, QueryNotUniqueError, + ServerConfigurationException, TransactionError, UniqueNamesError, UnqualifiedParentsError, UnqualifiedPropertiesError) @@ -1195,6 +1196,10 @@ class Entity(object): def _parse_value(datatype, value): + """Parse the value (from XML input) according to the given datatype + """ + + # Simple values if value is None: return value @@ -1215,12 +1220,12 @@ def _parse_value(datatype, value): else: raise ValueError("Boolean value was {}.".format(value)) + # Datetime and text are returned as-is if datatype in [DATETIME, TEXT]: if isinstance(value, str): return value # deal with collections - if isinstance(datatype, str): matcher = re.compile(r"^(?P<col>[^<]+)<(?P<dt>[^>]+)>$") m = matcher.match(datatype) @@ -1245,12 +1250,10 @@ def _parse_value(datatype, value): # This is for a special case, where the xml parser could not differentiate # between single values and lists with one element. As - if hasattr(value, "__len__") and len(value) == 1: return _parse_value(datatype, value[0]) # deal with references - if isinstance(value, Entity): return value @@ -1266,6 +1269,12 @@ def _parse_value(datatype, value): # reference via name return str(value) + except TypeError: + # deal with invalid XML: List of values without appropriate datatype + if isinstance(value, list): + raise ServerConfigurationException( + "The server sent an invalid XML: List valued properties must be announced by " + "the datatype.\n" + f"Datatype: {datatype}\nvalue: {value}") def _log_request(request, xml_body=None): diff --git a/unittests/data/list_in_value.xml b/unittests/data/list_in_value.xml index c3627cad313827e42350575ec3a297e281107211..0f92610d82caa5ced443b2f437f35da05b9e121a 100644 --- a/unittests/data/list_in_value.xml +++ b/unittests/data/list_in_value.xml @@ -8,3 +8,5 @@ <Value>1005</Value> </Property> </Record> + +<!-- Note: This XML is invalid, because list-valued Properties must have a LIST-Datatype --> diff --git a/unittests/test_issues.py b/unittests/test_issues.py index 84573c7917e87cbc33364f13a2d22c34a563bfb7..1e649db4f23de67e55301e0a053fba70d14680b4 100644 --- a/unittests/test_issues.py +++ b/unittests/test_issues.py @@ -24,10 +24,16 @@ import os import lxml import caosdb as db +from pytest import raises + def test_issue_100(): """_parse_value() fails for some list-valued content """ + + # Parse from (invalid) XML file filename = os.path.join(os.path.dirname(__file__), "data", "list_in_value.xml") xml_el = lxml.etree.parse(filename).getroot() - rec = db.common.models._parse_single_xml_element(xml_el) + with raises(db.ServerConfigurationException) as exc_info: + db.common.models._parse_single_xml_element(xml_el) + assert "invalid XML: List valued properties" in exc_info.value.msg