From 4fea5909af982b16645bcdb5eec3b381c08d459e Mon Sep 17 00:00:00 2001
From: Alexander Schlemmer <alexander@mail-schlemmer.de>
Date: Fri, 18 Feb 2022 14:16:23 +0100
Subject: [PATCH] MAINT: refactor add parent methods and added getters and
 setters

---
 src/caosdb/high_level_api.py | 135 +++++++++++++++++++++++++----------
 1 file changed, 98 insertions(+), 37 deletions(-)

diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py
index c8ae283b..5a509380 100644
--- a/src/caosdb/high_level_api.py
+++ b/src/caosdb/high_level_api.py
@@ -109,6 +109,46 @@ class CaosDBPythonEntity(object):
         # which must not be changed by the set_property function.
         self._forbidden = dir(self) + ["_forbidden"]
 
+    @property
+    def id(self):
+        """
+        Getter for the id.
+        """
+        return self._id
+
+    @id.setter
+    def id(self, val: int):
+        self._id = val
+
+    @property
+    def name(self):
+        """
+        Getter for the name.
+        """
+        return self._name
+
+    @name.setter
+    def name(self, val: str):
+        self._name = name
+
+    @property
+    def description(self):
+        """
+        Getter for the description.
+        """
+        return self._description
+
+    @description.setter
+    def description(self, val: str):
+        self._description = description
+
+    @property
+    def version(self):
+        """
+        Getter for the version.
+        """
+        return self._version
+
     # @staticmethod
     # def _get_new_id():
     #     """
@@ -222,16 +262,15 @@ class CaosDBPythonEntity(object):
         else:
             self.__setattr__(name, value)
 
-    # add_property = set_property
-
-    def set_id(self, idx: int):
+    def __setattr__(self, name: str, val: Any):
         """
-        Explicitely set the id of this entity.
-
-        idx: int
-             The new ID for this entity.
+        Allow setting generic properties.
         """
-        self._id = idx
+
+        # TODO: implement checking the value to correspond to one of the datatypes
+        #       known for conversion.
+
+        super().__setattr__(name, val)
 
     def _type_converted_list(self,
                              val: List,
@@ -247,10 +286,9 @@ class CaosDBPythonEntity(object):
         """
         if not is_list_datatype(pr):
             raise RuntimeError("Not a list.")
-        prreal = get_list_datatype(pr)
-        lst = [self._type_converted_value(i, prreal) for i in val]
 
-        return ([i[0] for i in lst], lst[0][1])
+        return [
+            self._type_converted_value(i, get_list_datatype(pr)) for i in val]
 
     def _type_converted_value(self,
                               val: Any,
@@ -279,7 +317,7 @@ class CaosDBPythonEntity(object):
         elif pr == REFERENCE:
             return CaosDBPythonUnresolvedReference(val)
         elif pr == DATETIME:
-            return val
+            return self._parse_datetime(val)
         elif is_list_datatype(pr):
             return self._type_converted_list(val, pr)
         elif isinstance(val, db.Entity):
@@ -288,50 +326,75 @@ class CaosDBPythonEntity(object):
             # Generic references to entities:
             return CaosDBPythonUnresolvedReference(val)
 
-    def _parse_datetime(self, val):
+    def _parse_datetime(self, val: Union[str, datetime]):
         """
         Convert val into a datetime object.
         """
+        if isinstance(val, datetime):
+            return val
         # TODO: try different representations
         return datetime.strptime("%Y-%m-%d %H:%M:%S", val)
 
-    def attribute_as_list(self, name):
-        """This is a workaround for the problem that lists containing only one
-        element are indistinguishable from simple types in this
-        representation."""
+    def get_property(self, name: str):
+        """
+        Return the value of the property with name name.
+
+        Raise an exception if the property does not exist.
+        """
+        if not self.property_exists(name):
+            raise RuntimeError("Property {} does not exist.".format(name))
         att = self.__getattribute__(name)
+        return att
+
+    def attribute_as_list(self, name: str):
+        """
+        This is a workaround for the problem that lists containing only one
+        element are indistinguishable from simple types in this
+        representation.
+
+        TODO: still relevant? seems to be only a problem if LIST types are not used.
+        """
+        att = self.get_property(name)
 
         if isinstance(att, list):
             return att
         else:
             return [att]
 
-    def _add_parent(self, parent):
+    def add_parent(self, parent: Union[
+            CaosDBPythonUnresolvedParent,
+            CaosDBPythonRecordType]):
         """
-        TODO
+        Add a parent to this entity. Either using an unresolved parent or
+        using a real record type.
         """
-        self._parents.append(parent.id)
 
-    def add_parent(self, parent_id=None, parent_name=None):
+        if self.has_parent(parent):
+            raise RuntimeError("Duplicate parent.")
+        self._parents.add(parent)
+
+    def has_parent(self, parent: Union[
+            CaosDBPythonUnresolvedParent,
+            CaosDBPythonRecordType]):
         """
-        TODO
+        Check whether this parent already exists for this entity.
         """
-        if parent_id is not None:
-            self._parents.append(parent_id)
-        elif parent_name is not None:
-            self._parents.append(parent_name)
-        else:
-            raise ValueError("no parent identifier supplied")
+        for p in self._parents:
+            if p.id == parent.id:
+                return True
+            elif p.name == parent.name:
+                return True
+        return False
 
-    def get_parent_names(self):
-        new_plist = []
+    # def get_parent_names(self):
+    #     new_plist = []
 
-        for p in self._parents:
-            obj_type = get_type_of_entity_with(p)
-            ent = obj_type(id=p).retrieve()
-            new_plist.append(ent.name)
+    #     for p in self._parents:
+    #         obj_type = get_type_of_entity_with(p)
+    #         ent = obj_type(id=p).retrieve()
+    #         new_plist.append(ent.name)
 
-        return new_plist
+    #     return new_plist
 
     def resolve_references(self, deep=False, visited=dict()):
         for i in self._references:
@@ -395,8 +458,6 @@ class CaosDBPythonProperty(CaosDBPythonEntity):
     pass
 
 
-
-
 class CaosDBPythonFile(CaosDBPythonEntity):
     def get_File(self, target=None):
         f = db.File(id=self._id).retrieve()
-- 
GitLab