diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py index d90ef0d55bb081d71d6dd04784cc013c77e9fd3e..12b2b32060aeece374f560f7be4fe7a741c07db6 100644 --- a/src/caosdb/apiutils.py +++ b/src/caosdb/apiutils.py @@ -357,14 +357,14 @@ def merge_entities(entity_a: Entity, entity_b: Entity): for key in diff_r2["properties"]: if key in diff_r1["properties"]: if ("importance" in diff_r1["properties"][key] and - "importance" in diff_r2["properties"][key]): + "importance" in diff_r2["properties"][key]): if (diff_r1["properties"][key]["importance"] != - diff_r2["properties"][key]["importance"]): + diff_r2["properties"][key]["importance"]): raise NotImplementedError() elif ("importance" in diff_r1["properties"][key] or "importance" in diff_r2["properties"][key]): raise NotImplementedError() - + for attribute in ("datatype", "unit", "value"): if diff_r1["properties"][key][attribute] is None: setattr(entity_a.get_property(key), attribute, @@ -503,7 +503,7 @@ def create_flat_list(ent_list: list[Entity], flat: list[Entity]): if isinstance(el, Entity): if el not in flat: flat.append(el) - create_flat_list([el], flat) # TODO: move inside if block? + create_flat_list([el], flat) # TODO: move inside if block? elif isinstance(p.value, Entity): if p.value not in flat: flat.append(p.value) diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py index 697ef2d38a828144d9f4f9ea7959e6ab43cbb4cf..03dd208e51cc5f2ed461ee156d935f71aba15bb3 100644 --- a/src/caosdb/high_level_api.py +++ b/src/caosdb/high_level_api.py @@ -90,7 +90,7 @@ def high_level_type_for_role(role: str): if role == "Entity": return CaosDBPythonEntity raise RuntimeError("Unknown role.") - + def high_level_type_for_standard_type(standard_record: db.Entity): if not isinstance(standard_record, db.Entity): @@ -273,7 +273,7 @@ class CaosDBPythonEntity(object): if ent.name in self.get_properties(): raise RuntimeError("Multiproperty not implemented yet.") - + val = self._type_converted_value(ent.value, ent.datatype, references) self.set_property( @@ -281,7 +281,7 @@ class CaosDBPythonEntity(object): val, datatype=ent.datatype) metadata = self.get_property_metadata(ent.name) - + for prop_name in fields(metadata): k = prop_name.name if k == "importance": @@ -302,7 +302,7 @@ class CaosDBPythonEntity(object): prop_name: str Name of the property to retrieve metadata for. """ - + if not self.property_exists(prop_name): raise RuntimeError("The property with name {} does not exist.".format(prop_name)) @@ -331,10 +331,10 @@ class CaosDBPythonEntity(object): name: str Name of the property. - + value: Any Value of the property. - + overwrite: bool Use this if you definitely only want one property with that name (set to True). @@ -344,7 +344,7 @@ class CaosDBPythonEntity(object): raise RuntimeError("Entity cannot be converted to a corresponding " "Python representation. Name of property " + name + " is forbidden!") - + already_exists = self.property_exists(name) if already_exists and not overwrite: @@ -515,7 +515,7 @@ class CaosDBPythonEntity(object): if isinstance(parent, int): parent = CaosDBPythonUnresolvedParent(id=parent) - + for p in self._parents: if p.id is not None and p.id == parent.id: return True @@ -599,7 +599,7 @@ class CaosDBPythonEntity(object): else: resolvedelements.append(element) self.__setattr__(prop, resolvedelements) - + elif isinstance(propval, CaosDBPythonUnresolvedReference): val = self._resolve_caosdb_python_unresolved_reference(propval, deep, references, visited) @@ -658,8 +658,7 @@ class CaosDBPythonEntity(object): entity.deserialize(prop)) else: entity.__setattr__(p, prop) - - + # if there is no metadata in the yaml file just initialize an empty metadata object if "metadata" in serialization and p in serialization["metadata"]: metadata = serialization["metadata"][p] @@ -672,7 +671,6 @@ class CaosDBPythonEntity(object): raise NotImplementedError() return entity - def serialize(self, without_metadata: bool = False, visited: dict = None): """ @@ -688,7 +686,7 @@ class CaosDBPythonEntity(object): if self in visited: return visited[self] - + metadata: dict[str, Any] = dict() properties = dict() parents = list() @@ -713,7 +711,7 @@ class CaosDBPythonEntity(object): val = self.__getattribute__(baseprop) if val is not None: fulldict[baseprop] = val - + if type(self) == CaosDBPythonFile: fulldict["file"] = self.file fulldict["path"] = self.path @@ -748,10 +746,10 @@ class CaosDBPythonEntity(object): properties[p] = serializedelements else: properties[p] = val - + fulldict["properties"] = properties fulldict["parents"] = parents - + if not without_metadata: fulldict["metadata"] = metadata return fulldict @@ -782,7 +780,7 @@ class CaosDBMultiProperty: """ This implements a multi property using a python list. """ - + def __init__(self): raise NotImplementedError() @@ -832,6 +830,7 @@ def _single_convert_to_python_object(robj: CaosDBPythonEntity, return robj + def _convert_property_value(propval): if isinstance(propval, CaosDBPythonUnresolvedReference): propval = propval.id @@ -842,9 +841,10 @@ def _convert_property_value(propval): propval = [_convert_property_value(element) for element in propval] # TODO: test case for list missing - + return propval + def _single_convert_to_entity(entity: db.Entity, robj: CaosDBPythonEntity): """ @@ -864,9 +864,9 @@ def _single_convert_to_entity(entity: db.Entity, # Skip version: if base_attribute == "version": continue - + val = robj.__getattribute__(base_attribute) - + if val is not None: entity.__setattr__(base_attribute, val) @@ -883,7 +883,7 @@ def _single_convert_to_entity(entity: db.Entity, metadata = robj.get_property_metadata(prop) propval = _convert_property_value(propval) - + entity.add_property( name=prop, value=propval, @@ -932,7 +932,7 @@ def convert_to_python_object(entity: Union[db.Container, db.Entity], return _single_convert_to_python_object( high_level_type_for_standard_type(entity)(), entity, references) - + def new_high_level_entity(entity: db.RecordType, importance_level: str, @@ -967,8 +967,8 @@ def new_high_level_entity(entity: db.RecordType, r.add_property(prop) return convert_to_python_object(r) - - + + def create_record(rtname: str, name: str = None, **kwargs): """ Create a new record based on the name of a record type. The new record is returned. @@ -1006,11 +1006,11 @@ def create_entity_container(record: CaosDBPythonEntity): lse: List[db.Entity] = [ent] create_flat_list([ent], lse) return db.Container().extend(lse) - + def query(query: str, resolve_references: bool = True, references: db.Container = None): """ - + """ res = db.execute_query(query) objects = convert_to_python_object(res) diff --git a/src/caosdb/utils/plantuml.py b/src/caosdb/utils/plantuml.py index 2cc1bb53e50aca7b26dc2ade423f010f43f6a774..412d97d443c7561efdcc527b92b842d5416c1bd7 100644 --- a/src/caosdb/utils/plantuml.py +++ b/src/caosdb/utils/plantuml.py @@ -168,8 +168,6 @@ hide circle\n else: raise ValueError("Unknown style.") - - if add_properties: result += "package Properties #DDDDDD {\n" for p in properties: @@ -293,7 +291,7 @@ def retrieve_substructure(start_record_types, depth, result_id_set=None, result_ if is_reference(prop.datatype) and prop.datatype != db.FILE and depth > 0: rt = db.RecordType(name=get_referenced_recordtype(prop.datatype)).retrieve() retrieve_substructure([rt], depth-1, result_id_set, result_container, False) - + # TODO: clean up this hack # TODO: make it also work for files if is_reference(prop.datatype) and prop.value is not None: @@ -358,13 +356,13 @@ def to_graphics(recordtypes: list[db.Entity], filename: str, if output_dirname is None: output_dirname = os.getcwd() - + allowed_formats = [ "tpng", "tsvg", "teps", "tpdf", "tvdx", "txmi", "tscxml", "thtml", "ttxt", "tutxt", "tlatex", "tlatex:nopreamble"] with tempfile.TemporaryDirectory() as td: - + pu_filename = os.path.join(td, filename + ".pu") with open(pu_filename, "w") as pu_file: pu_file.write(pu) @@ -373,7 +371,7 @@ def to_graphics(recordtypes: list[db.Entity], filename: str, extension = format[1:] if ":" in extension: extension = extension[:extension.index(":")] - + if format not in allowed_formats: raise RuntimeError("Format not allowed.") cmd = "plantuml -{} {}".format(format, pu_filename) diff --git a/unittests/test_apiutils.py b/unittests/test_apiutils.py index bc747f8ed67d5310a4bcd26af9de3a66958e1fd3..fcedc380d15c06acaf93122922e513d025a1563e 100644 --- a/unittests/test_apiutils.py +++ b/unittests/test_apiutils.py @@ -32,7 +32,6 @@ from caosdb.apiutils import (apply_to_ids, compare_entities, create_id_query, resolve_reference, copy_entity, merge_entities) - def test_apply_to_ids(): parent = db.RecordType(id=3456) rec = db.Record(id=23) @@ -234,4 +233,3 @@ def test_copy_entities(): assert c.properties[i] != r.properties[i] assert c.properties[i].value == r.properties[i].value assert c.get_importance(c.properties[i]) == r.get_importance(r.properties[i]) - diff --git a/unittests/test_high_level_api.py b/unittests/test_high_level_api.py index bca279cd49bf75a622c033dba2fd559657c7c201..a9e55c9c2a79f7ead8bbb3fb652c1b81427e69e9 100644 --- a/unittests/test_high_level_api.py +++ b/unittests/test_high_level_api.py @@ -23,7 +23,6 @@ # A. Schlemmer, 02/2022 - import caosdb as db from caosdb.high_level_api import (convert_to_entity, convert_to_python_object, new_high_level_entity) @@ -46,7 +45,10 @@ import os import tempfile import pickle -import sys, traceback, pdb +import sys +import traceback +import pdb + @pytest.fixture def testrecord(): @@ -115,7 +117,7 @@ def test_convert_record(): def test_convert_with_references(): r_ref = db.Record() r_ref.add_property(name="a", value=42) - + r = db.Record() r.add_property(name="ref", value=r_ref) @@ -131,7 +133,7 @@ def test_convert_with_references(): r_ref = db.Record() r_ref.add_parent("bla") r_ref.add_property(name="a", value=42) - + r = db.Record() r.add_property(name="ref", value=r_ref) @@ -145,7 +147,7 @@ def test_convert_with_references(): r_ref = db.Record() r_ref.add_parent("bla") r_ref.add_property(name="a", value=42) - + r = db.Record() r.add_property(name="ref", value=r_ref, datatype="bla") @@ -237,6 +239,7 @@ def test_resolve_references(): obj.resolve_references(True, references) assert obj.ref.ref.ref == obj.ref + def equal_entities(r1, r2): res = compare_entities(r1, r2) if len(res) != 2: @@ -245,7 +248,8 @@ def equal_entities(r1, r2): if len(res[i]["parents"]) != 0 or len(res[i]["properties"]) != 0: return False return True - + + def test_conversion_to_entity(): r = db.Record() r.add_parent("bla") @@ -255,12 +259,11 @@ def test_conversion_to_entity(): rconv = convert_to_entity(obj) assert equal_entities(r, rconv) - # With a reference: r_ref = db.Record() r_ref.add_parent("bla") r_ref.add_property(name="a", value=42) - + r = db.Record() r.add_property(name="ref", value=r_ref) obj = convert_to_python_object(r) @@ -269,6 +272,7 @@ def test_conversion_to_entity(): == r.get_property("ref").value.get_property("a").value) # TODO: add more tests here + def test_base_properties(): r = db.Record(id=5, name="test", description="ok") r.add_property(name="v", value=15, datatype=db.INTEGER, unit="kpx", @@ -295,6 +299,7 @@ def test_base_properties(): assert prop.description == "description" assert rconv.get_importance("v") == "RECOMMENDED" + def test_empty(): r = db.Record() obj = convert_to_python_object(r) @@ -305,6 +310,7 @@ def test_empty(): rconv = convert_to_entity(obj) assert len(rconv.properties) == 0 + def test_wrong_entity_for_file(): r = db.Record() r.path = "test.dat" @@ -422,7 +428,7 @@ def test_record_generator(): print(obj) assert False - + def test_list_types(): r = db.Record() r.add_property(name="a", value=[1, 2, 4]) @@ -495,7 +501,7 @@ def test_list_types(): r2.add_property(name="a", value=4) r3 = db.Record() r3.add_property(name="b", value=8) - + r = db.Record() r.add_property(name="a", value=[r2, r3]) @@ -572,7 +578,6 @@ def test_deserialization(): assert obj_des.file == "bla.test" assert obj_des.path == "/test/n/bla.test" - r = db.Record(id=17, name="test") r.add_parent("bla") r.add_property(name="a", value=42) @@ -591,6 +596,7 @@ def test_deserialization(): obj_des = CaosDBPythonEntity.deserialize(serial) assert obj.serialize() == obj_des.serialize() + @pytest.fixture def get_record_container(): record_xml = """ @@ -612,6 +618,7 @@ def get_record_container(): c = db.Container.from_xml(record_xml) return c + def test_recursion(get_record_container): r = convert_to_python_object(get_record_container[0]) r.resolve_references(r, get_record_container) @@ -623,7 +630,8 @@ def test_recursion(get_record_container): d = r.serialize(True) assert r.sources[0] == r.sources[0].sources[0] - + + @pytest.mark.xfail def test_recursion_advanced(get_record_container): # TODO: