diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py index 2c08565a2bfae6f8eefaebdb705b300c5c5f636b..345f02d6a490c6a20beb27e8d3250aef6fa22e5d 100644 --- a/src/caosdb/high_level_api.py +++ b/src/caosdb/high_level_api.py @@ -478,7 +478,10 @@ class CaosDBPythonEntity(object): for prop in self.get_properties(): propval = self.__getattribute__(prop) - if isinstance(propval, CaosDBPythonUnresolvedReference): + # Resolve all previously unresolved attributes that are entities: + if deep and isinstance(propval, CaosDBPythonEntity): + propval.resolve_references(deep, references) + elif isinstance(propval, CaosDBPythonUnresolvedReference): # This does not make sense for unset ids: if propval.id is None: raise RuntimeError("Unresolved property reference without an ID.") diff --git a/unittests/test_high_level_api.py b/unittests/test_high_level_api.py index 72ac2bc340caaf6a6518b24ec3bfa875bfaa0582..a5a123107f65c4a77e5cb3270ffbee60e738ffee 100644 --- a/unittests/test_high_level_api.py +++ b/unittests/test_high_level_api.py @@ -27,7 +27,8 @@ import caosdb as db from caosdb.high_level_api import (convert_to_entity, convert_to_python_object) from caosdb.high_level_api import (CaosDBPythonUnresolvedParent, - CaosDBPythonUnresolvedReference) + CaosDBPythonUnresolvedReference, + CaosDBPythonRecord) import pytest from lxml import etree import os @@ -152,3 +153,76 @@ def test_convert_with_references(): assert obj.get_property_metadata("ref").datatype is "bla" assert isinstance(obj.ref, CaosDBPythonUnresolvedReference) assert obj.ref.id == 27 + + +def test_resolve_references(): + r = db.Record() + r.add_property(name="ref", value=27, datatype="bla") + r.add_property(name="ref_false", value=27) # this should be interpreted as integer property + obj = convert_to_python_object(r) + + ref = db.Record(id=27) + ref.add_property(name="a", value=57) + + unused_ref1 = db.Record(id=28) + unused_ref2 = db.Record(id=29) + unused_ref3 = db.Record(name="bla") + + references = db.Container().extend([ + unused_ref1, ref, unused_ref2, unused_ref3]) + + # Nothing is going to be resolved: + obj.resolve_references(False, db.Container()) + assert isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.id == 27 + assert obj.ref_false == 27 + + # deep == True does not help: + obj.resolve_references(True, db.Container()) + assert isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.id == 27 + + # But adding the reference container will do: + obj.resolve_references(False, references) + assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert isinstance(obj.ref, CaosDBPythonRecord) + assert obj.ref.id == 27 + assert obj.ref.a == 57 + # Datatypes will not automatically be set: + assert obj.ref.get_property_metadata("a").datatype is None + + # Test deep resolve: + ref2 = db.Record(id=225) + ref2.add_property(name="c", value="test") + ref.add_property(name="ref", value=225, datatype="bla") + + obj = convert_to_python_object(r) + assert isinstance(obj.ref, CaosDBPythonUnresolvedReference) + obj.resolve_references(False, references) + assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.ref.id == 225 + + # Will not help, because ref2 is missing in container: + obj.resolve_references(True, references) + assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.ref.id == 225 + + references.append(ref2) + obj.resolve_references(False, references) + assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.ref.id == 225 + + obj.resolve_references(True, references) + assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference) + assert not isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference) + assert obj.ref.ref.c == "test" + + # Test circular dependencies: + ref2.add_property(name="ref", value=27, datatype="bla") + obj = convert_to_python_object(r) + obj.resolve_references(True, references) + assert obj.ref.ref.ref == obj.ref +