From f1e50bdb2b303fef578ece6333171db1c22d1274 Mon Sep 17 00:00:00 2001
From: fspreck <f.spreckelsen@indiscale.com>
Date: Fri, 3 Jul 2020 14:18:14 +0200
Subject: [PATCH] WIP: Implement classes TransactionError and EntityError

All other classes can remain as they are right now.
---
 src/caosdb/exceptions.py | 142 +++++++++++++++++++--------------------
 1 file changed, 71 insertions(+), 71 deletions(-)

diff --git a/src/caosdb/exceptions.py b/src/caosdb/exceptions.py
index 874e62f5..a28a2394 100644
--- a/src/caosdb/exceptions.py
+++ b/src/caosdb/exceptions.py
@@ -153,7 +153,6 @@ class TransactionError(CaosDBException):
         self.msg = msg
         if error is not none:
             self.add_error(error)
-        
 
     def print_errs(self):
         print(self)
@@ -165,7 +164,7 @@ class TransactionError(CaosDBException):
         """Check whether this transaction error contains an error of type
         error_t. If direct_children_only is True, only direct children
         are checked.
-        
+
         Parameters:
         -----------
         error_t : EntityError
@@ -204,21 +203,67 @@ class TransactionError(CaosDBException):
             return self
         elif isinstance(error, EntityError):
             self.errors.append(error)
+            self.entities.append(error.get_entity())
+
+            self.all_errors.append(error)
+            self.all_errors.extend(error.get_all_errors())
+            self.all_entities.append(error.get_entity())
+            self.all_entities.extend(error.get_all_entities())
 
             return self
         else:
             raise TypeError(
-                "Argument is to be an TransactionError or a list of TransactionErrors.")
+                "Argument is to be an EntityError or a list of EntityErrors.")
 
     def get_errors(self):
-        '''
-        @return: A list of all EntityError objects.
-        '''
+        """Return a list of all direct children of this error."""
+
+        return self.errors
+
+    def get_all_errors(self):
+        """Return a set of all direct and inidrect children of this error."""
+
+        return self.all_errors
+
+    def get_entities(self):
+        """Return a list of all entities causing direct child errors."""
+
+        return self.entities
+
+    def get_all_entities(self):
+        """Return a set of all entities causing direct and indirect child
+        errors.
+
+        """
+
+        return self.all_entities
+
+    def get_error(self):
+        """If this Transaction error was caused by exactly one EntityError,
+        return this error. Raise an AmbiguityException otherwise.
+
+        """
 
-        if hasattr(self, 'errors'):
-            return self.errors
+        if len(self.errors) == 1:
+            return self.errors[0].get_error()
+        else:
+            raise AmbiguityException(
+                "This TransactionError was caused by more than one EntityError."
+            )
 
-        return None
+    def get_entity(self):
+        """If this TransactionError was caused by exactly one EntityError,
+        return the entity causing that error. Raise and
+        AmbiguityException otherwise.
+
+        """
+
+        if len(self.entities) == 1:
+            return self.entities[0]
+        else:
+            raise AmbiguityException(
+                "This TransActionError was caused by more than one EntityError."
+            )
 
     def _repr_reasons(self, indent):
         if self.get_errors() is not None and len(self.get_errors()) > 0:
@@ -246,57 +291,15 @@ class TransactionError(CaosDBException):
     def __repr__(self):
         return self.__str__()
 
-    def get_entities(self):
-        '''
-        @return: A list of all Entity objects with errors.
-        '''
-        ret = []
-
-        if hasattr(self, 'get_entity') and self.get_entity() is not None:
-            ret.append(self.get_entity())
-
-        for error in self.errors:
-            if hasattr(error, 'get_entity'):
-                if error.get_entity() not in ret:
-                    ret.append(error.get_entity())
-#             if hasattr(error, 'get_entities'):
-#                 for e in error.get_entities():
-#                     if e not in ret:
-#                         ret.append(e)
-        return ret
-
-    def get_error(self):
-        return self.error
-
 
 class EntityError(TransactionError):
+    """This is the most basic entity error. It is constructed using an
+    entity that caused the error and the error message attached by the
+    server.
 
-    @staticmethod
-    def _sort_t(t):
-        if len(t) > 1:
-            ret = ()
-            '''remove EntityError'''
-
-            for i in range(len(t)):
-                if t[i] != EntityError:
-                    ret += (t[i],)
-            t = ret
-
-        return t
-
-    def _convert(self):
-        t = self._calc_bases()
-        # TODO is it really a good idea to create dynamically types here?
-        newtype = type('EntityMultiError', t+(Exception,), {})
-        newinstance = newtype(error=self.error, entity=self.entity)
-        setattr(newinstance, 'msg', self.msg)
-        setattr(newinstance, 'errors', self.errors)
-        setattr(newinstance, 'container', self.container)
-
-        return newinstance
-
-    def __init__(self, error=None, container=None, entity=None):
-        TransactionError.__init__(self, container=container)
+    """
+    def __init__(self, error=None, entity=None):
+        TransactionError.__init__(self)
         self.error = error
         self.entity = entity
 
@@ -310,15 +313,15 @@ class EntityError(TransactionError):
             self.msg = str(error)
 
     def get_entity(self):
-        '''
-        @return: The entity that caused this error.
-        '''
+        """Return the entity causing this error."""
 
-        if hasattr(self, 'entity'):
-            return self.entity
+        return self.entity
 
-        return None
+    def get_error(self):
+        """Return this error message as attached by the server."""
 
+        return self.error
+    
     @property
     def description(self):
         return self.error.description if self.error is not None else None
@@ -326,17 +329,14 @@ class EntityError(TransactionError):
     def get_code(self):
         return self.error.code if self.error is not None else None
 
-    def get_error(self):
-        '''
-        @return: Error Message object of this Error.
-        '''
-
-        return self.error
+    
 
     def _repr_head(self, indent):
         if hasattr(self, 'entity') and self.entity is not None:
-            return str(type(self.entity).__name__).upper() + " (" + str(self.entity.id) + (("," + "'" + str(self.entity.name) + "'")
-                                                                                           if self.entity.name is not None else '') + ") CAUSED " + TransactionError._repr_head(self, indent)
+            return (str(type(self.entity).__name__).upper() + " (" +
+                    str(self.entity.id) + (("," + "'" + str(self.entity.name) + "'") if
+                                           self.entity.name is not None else '') + ") CAUSED " +
+                    TransactionError._repr_head(self, indent))
         else:
             return TransactionError._repr_head(self, indent)
 
-- 
GitLab