From df8f9231f490e62ee55c36c369184cbbfc09ca27 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 3 Jan 2025 14:58:08 +0100
Subject: [PATCH 1/3] ENH: add new member function filter to Container class

---
 CHANGELOG.md                   |  1 +
 src/linkahead/common/models.py | 40 +++++++++++++++++++++++++++++-----
 2 files changed, 35 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1fd615..8fe5c3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ### Added ###
 
 * New setup extra `test` which installs the dependencies for testing.
+* The Container class has a new member function `filter` which is based o `_filter_entity_list`.
 
 ### Changed ###
 
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index 1caa6a4..031d805 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -2575,8 +2575,6 @@ class PropertyList(list):
 
         Params
         ------
-        listobject        : Iterable(Property)
-                            List to be filtered
         prop              : Property
                             Property to match name and ID with. Cannot be set
                             simultaneously with ID or name.
@@ -3093,12 +3091,12 @@ def _basic_sync(e_local, e_remote):
     if e_local.role is None:
         e_local.role = e_remote.role
     elif e_remote.role is not None and not e_local.role.lower() == e_remote.role.lower():
-        raise ValueError("The resulting entity had a different role ({0}) "
-                         "than the local one ({1}). This probably means, that "
+        raise ValueError(f"The resulting entity had a different role ({e_remote.role}) "
+                         f"than the local one ({e_local.role}). This probably means, that "
                          "the entity was intialized with a wrong class "
                          "by this client or it has changed in the past and "
-                         "this client did't know about it yet.".format(
-                             e_remote.role, e_local.role))
+                         "this client did't know about it yet.\nThis is the local version of the"
+                         f" Entity:\n{e_local}\nThis is the remote one:\n{e_remote}")
 
     e_local.id = e_remote.id
     e_local.name = e_remote.name
@@ -3730,6 +3728,36 @@ class Container(list):
 
         return sync_dict
 
+    def filter(self, entity: Optional[Entity] = None,
+               pid: Union[None, str, int] = None,
+               name: Optional[str] = None,
+               conjunction: bool = False) -> list:
+        """
+        Return all Entities from this Container that match the selection criteria.
+
+        Please refer to the documentation of _filter_entity_list for a detailed
+        description of behaviour.
+
+        Params
+        ------
+        entity            : Entity
+                            Entity to match name and ID with
+        pid               : str, int
+                            Parent ID to match
+        name              : str
+                            Parent name to match
+                            simultaneously with ID or name.
+        conjunction       : bool, defaults to False
+                            Set to return only entities that match both id and name
+                            if both are given.
+
+        Returns
+        -------
+        matches          : list
+                           List containing all matching Entities
+        """
+        return _filter_entity_list(self, pid=pid, name=name, entity=entity,
+                                   conjunction=conjunction)
     @staticmethod
     def _find_dependencies_in_container(container: Container):
         """Find elements in a container that are a dependency of another element of the same.
-- 
GitLab


From 1f2c002304e7b9e4b053fb6ee8321972faad0532 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 3 Jan 2025 15:03:53 +0100
Subject: [PATCH 2/3] TST: add test for filter function of Container

---
 unittests/test_container.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/unittests/test_container.py b/unittests/test_container.py
index c3a6014..4ef8591 100644
--- a/unittests/test_container.py
+++ b/unittests/test_container.py
@@ -199,3 +199,12 @@ def test_container_slicing():
 
     with pytest.raises(TypeError):
         cont[[0, 2, 3]]
+
+def test_container_filter():
+    # this is a very rudimentary test since filter is based on _filter_entity_list which is tested
+    # separately
+    cont = db.Container()
+    cont.extend([db.Record(name=f"TestRec{ii+1}") for ii in range(5)])
+    recs = cont.filter(name="TestRec2")
+    assert len(recs)==1
+    recs[0].name =="TestRec2"
-- 
GitLab


From cea96eee220e16258aea5320e20d9dfa7cd04974 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 3 Jan 2025 15:11:01 +0100
Subject: [PATCH 3/3] DOC: document new filter function

---
 src/doc/tutorials/complex_data_models.rst | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/doc/tutorials/complex_data_models.rst b/src/doc/tutorials/complex_data_models.rst
index 168cf3b..6c9520c 100644
--- a/src/doc/tutorials/complex_data_models.rst
+++ b/src/doc/tutorials/complex_data_models.rst
@@ -78,7 +78,7 @@ Examples
 
 
 Finding parents and properties
---------
+------------------------------
 To find a specific parent or property of an Entity, its
 ParentList or PropertyList can be filtered using names, ids, or
 entities. A short example:
@@ -126,3 +126,19 @@ entities. A short example:
    # Result: [p2_1]
 
 The filter function of ParentList works analogously.
+
+Finding entities in a Container
+-------------------------------
+In the same way as described above, Container can be filtered.
+A short example:
+
+.. code-block:: python3
+
+   import linkahead as db
+
+   # Setup a record with six properties
+   p1 = db.Property(id=101, name="Property 1")
+   p2 = db.Property(name="Property 2")
+   c = db.Container().extend([p1,p2])
+   c.filter(name="Property 1")
+   # Result: [p1]
-- 
GitLab