From 666d6d417fdb32ade1324690c10a37c301c2afc9 Mon Sep 17 00:00:00 2001 From: Alexander Schlemmer <alexander@mail-schlemmer.de> Date: Fri, 7 Jul 2023 10:24:47 +0200 Subject: [PATCH] FIX: problems with cyclic references in high level api --- src/caosdb/high_level_api.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py index 005a20bb..ce65915e 100644 --- a/src/caosdb/high_level_api.py +++ b/src/caosdb/high_level_api.py @@ -561,8 +561,8 @@ class CaosDBPythonEntity(object): return propval def resolve_references(self, deep: bool, references: db.Container, - visited: Dict[Union[str, int], - "CaosDBPythonEntity"] = None): + visited: Optional[Dict[Union[str, int], + "CaosDBPythonEntity"]] = None): """ Resolve this entity's references. This affects unresolved properties as well as unresolved parents. @@ -807,7 +807,9 @@ BASE_ATTRIBUTES = ( def _single_convert_to_python_object(robj: CaosDBPythonEntity, entity: db.Entity, - references: Optional[db.Container] = None): + references: Optional[db.Container] = None, + visited: Optional[Dict[int, + "CaosDBPythonEntity"]] = None): """ Convert a db.Entity from the standard API to a (previously created) CaosDBPythonEntity from the high level API. @@ -822,6 +824,17 @@ def _single_convert_to_python_object(robj: CaosDBPythonEntity, Returns the input object robj. """ + + # This parameter is used in the recursion to keep track of already visited + # entites (in order to detect cycles). + if visited is None: + visited = dict() + + if id(entity) in visited: + return visited[id(entity)] + else: + visited[id(entity)] = robj + for base_attribute in BASE_ATTRIBUTES: val = entity.__getattribute__(base_attribute) if val is not None: @@ -924,7 +937,9 @@ def convert_to_entity(python_object): def convert_to_python_object(entity: Union[db.Container, db.Entity], - references: Optional[db.Container] = None): + references: Optional[db.Container] = None, + visited: Optional[Dict[int, + "CaosDBPythonEntity"]] = None): """ Convert either a container of CaosDB entities or a single CaosDB entity into the high level representation. @@ -936,15 +951,16 @@ def convert_to_python_object(entity: Union[db.Container, db.Entity], """ if isinstance(entity, db.Container): # Create a list of objects: - return [convert_to_python_object(i, references) for i in entity] + return [convert_to_python_object(i, references, visited) for i in entity] + # TODO: recursion problems? return _single_convert_to_python_object( - high_level_type_for_standard_type(entity)(), entity, references) + high_level_type_for_standard_type(entity)(), entity, references, visited) def new_high_level_entity(entity: db.RecordType, importance_level: str, - name: str = None): + name: Optional[str] = None): """ Create an new record in high level format based on a record type in standard format. -- GitLab