From ddd6d1fe8a33ea29e37da901b5aa0271f9ccdd3a Mon Sep 17 00:00:00 2001
From: "i.nueske" <i.nueske@indiscale.com>
Date: Fri, 25 Oct 2024 10:48:22 +0200
Subject: [PATCH] MNT: Extended some comments, removed extra spaces, added some
 ToDos

---
 src/linkahead/apiutils.py | 85 ++++++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 41 deletions(-)

diff --git a/src/linkahead/apiutils.py b/src/linkahead/apiutils.py
index fab8c14f..d70f937f 100644
--- a/src/linkahead/apiutils.py
+++ b/src/linkahead/apiutils.py
@@ -183,7 +183,7 @@ def compare_entities(old_entity: Entity,
                      new_entity: Entity,
                      compare_referenced_records: bool = False
                      ) -> tuple[dict[str, Any], dict[str, Any]]:
-    """Compare two entites.
+    """Compare two entities.
 
     The following attributes are compared:
     - parents
@@ -200,7 +200,7 @@ def compare_entities(old_entity: Entity,
         the following differs:
         - datatype
         - importance or
-        - value (not implemented yet)
+        - value
 
         In case of changed information the value listed under the respective key is the
         value that is stored in the respective entity.
@@ -226,31 +226,33 @@ def compare_entities(old_entity: Entity,
     newdiff: dict[str, Any] = {"properties": {}, "parents": []}
 
     if old_entity is new_entity:
-        return (olddiff, newdiff)
+        return olddiff, newdiff
 
     if type(old_entity) is not type(new_entity):
         raise ValueError(
             "Comparison of different Entity types is not supported.")
 
-    ### compare special attributes ###
+    # compare special attributes
     for attr in SPECIAL_ATTRIBUTES:
         if attr == "value":
             continue
+
         oldattr = old_entity.__getattribute__(attr)
-        # we considere "" and None as nonexistent
+        # we consider "" and None to be nonexistent
         old_entity_attr_na = (oldattr == "" or oldattr is None)
 
         newattr = new_entity.__getattribute__(attr)
-        # we considere "" and None as nonexistent
+        # we consider "" and None to be nonexistent
         new_entity_attr_na = (newattr == "" or newattr is None)
 
-        # both unset
+        # in both entities the current attribute is not set
         if old_entity_attr_na and new_entity_attr_na:
             continue
 
-        # treat datatype separately: if datatype is an object on one side and string on the other.
+        # treat datatype separately if one datatype is an object and the other
+        # a string or int, and may be a name or id
         if attr == "datatype":
-            if (not old_entity_attr_na and not new_entity_attr_na):
+            if not old_entity_attr_na and not new_entity_attr_na:
                 if isinstance(oldattr, RecordType):
                     if oldattr.name == newattr:
                         continue
@@ -262,8 +264,7 @@ def compare_entities(old_entity: Entity,
                     if newattr.id == oldattr:
                         continue
 
-
-        # only one set or different values
+        # add to diff if attribute has different values or is not set for one entity
         if ((old_entity_attr_na ^ new_entity_attr_na)
                 or (oldattr != newattr)):
             if not old_entity_attr_na:
@@ -272,27 +273,25 @@ def compare_entities(old_entity: Entity,
             if not new_entity_attr_na:
                 newdiff[attr] = newattr
 
-
-    # value
-    if (old_entity.value != new_entity.value):
-        # basic comparison of value objects says they are different
+    # compare value
+    if old_entity.value != new_entity.value:
+        # though the values are not equal, they might be equivalent:
         same_value = False
         if compare_referenced_records:
-            # scalar reference
+            # both values are scalar references:
             if isinstance(old_entity.value, Entity) and isinstance(new_entity.value, Entity):
-                # explicitely not recursive to prevent infinite recursion
+                # compare_referenced_records=False to prevent infinite recursion
                 same_value = empty_diff(
                     old_entity.value, new_entity.value, compare_referenced_records=False)
-            # list of references
+            # both values are a list of references:
             elif isinstance(old_entity.value, list) and isinstance(new_entity.value, list):
-                # all elements in both lists actually are entity objects
-                # TODO: check, whether mixed cases can be allowed or should lead to an error
+                # if all elements in both lists are entity objects, check each pair for equality
+                # TODO: check whether mixed cases should be allowed or lead to an error
                 if (all([isinstance(x, Entity) for x in old_entity.value])
                         and all([isinstance(x, Entity) for x in new_entity.value])):
-                    # can't be the same if the lengths are different
+                    # lists can't be the same if the lengths are different
                     if len(old_entity.value) == len(new_entity.value):
-                        # do a one-by-one comparison:
-                        # the values are the same if all diffs are empty
+                        # the lists are the same if the diffs of each entry pair are empty
                         same_value = all(
                             [empty_diff(x, y, False) for x, y
                                 in zip(old_entity.value, new_entity.value)])
@@ -301,21 +300,24 @@ def compare_entities(old_entity: Entity,
             olddiff["value"] = old_entity.value
             newdiff["value"] = new_entity.value
 
-    # properties
+    # compare properties
     for prop in old_entity.properties:
         matching = [p for p in new_entity.properties if p.name.lower() == prop.name.lower()]
         if len(matching) == 0:
-            # old has prop and new does not
-            olddiff["properties"][prop.name]  = {}
+            # old_entity has prop, new_entity does not
+            olddiff["properties"][prop.name] = {}
         elif len(matching) ==1:
-            olddiff["properties"][prop.name]  = {}
-            newdiff["properties"][prop.name]  = {}
+            olddiff["properties"][prop.name] = {}
+            newdiff["properties"][prop.name] = {}
             oldpropdiff = olddiff["properties"][prop.name]
             newpropdiff = newdiff["properties"][prop.name]
 
-            # use compare function detect difference of properties
+            # recursive call to determine the differences between properties
+            # ToDo: This can lead to infinite recursion if two properties have
+            #       each other as subproperties
             od, nd = compare_entities(prop, matching[0], compare_referenced_records=compare_referenced_records)
-            # we do not care about parents and properties here # TODO do we?
+            # as we do not care about parents and properties here, discard their entries
+            # TODO do we?
             od.pop("parents")
             od.pop("properties")
             nd.pop("parents")
@@ -324,27 +326,28 @@ def compare_entities(old_entity: Entity,
             oldpropdiff.update(od)
             newpropdiff.update(nd)
 
-            # importance is associated with the record. So do it extra
-            if (old_entity.get_importance(prop.name) != new_entity.get_importance(prop.name)):
-                oldpropdiff["importance"] =  old_entity.get_importance(prop.name)
-                newpropdiff["importance"] =  new_entity.get_importance(prop.name)
+            # As the importance of a property is an attribute of the record and not
+            # the property, it is not contained in the diff returned by compare_entities
+            if old_entity.get_importance(prop.name) != new_entity.get_importance(prop.name):
+                oldpropdiff["importance"] = old_entity.get_importance(prop.name)
+                newpropdiff["importance"] = new_entity.get_importance(prop.name)
 
-            # in case there was actually no difference, we remove the dict keys again
-            if (len(newpropdiff) == 0 and len(oldpropdiff) == 0):
+            # in case there is no difference, we remove the dict keys again
+            if len(newpropdiff) == 0 and len(oldpropdiff) == 0:
                 newdiff["properties"].pop(prop.name)
                 olddiff["properties"].pop(prop.name)
         else:
             raise NotImplementedError(
                 "Comparison not implemented for multi-properties.")
 
-    # add the properties that are only present in new
+    # we have not yet compared properties that do not exist in old_entity
     for prop in new_entity.properties:
         if len([0 for p in old_entity.properties if p.name.lower() == prop.name.lower()]) == 0:
             newdiff["properties"][prop.name] = {}
 
-    # parents
-
-    # TODO we only use names for parents and property matching
+    # compare parents
+    # ToDo: Compare using filter function, compare inheritance level for RTs
+    # TODO we currently only use names for parents and property matching
     for parent in old_entity.parents:
         if len([0 for p in new_entity.parents if p.name.lower() == parent.name.lower()]) == 0:
             olddiff["parents"].append(parent.name)
@@ -353,7 +356,7 @@ def compare_entities(old_entity: Entity,
         if len([0 for p in old_entity.parents if p.name.lower() == parent.name.lower()]) == 0:
             newdiff["parents"].append(parent.name)
 
-    return (olddiff, newdiff)
+    return olddiff, newdiff
 
 
 def empty_diff(old_entity: Entity, new_entity: Entity,
-- 
GitLab