From dbeef18c62e26bd61a087fc3e478731444ccce88 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 10 Jan 2025 09:24:51 +0100
Subject: [PATCH 1/3] MAINT: rename filter to filter_by_identity

---
 CHANGELOG.md                              |   1 +
 src/doc/tutorials/complex_data_models.rst |  14 +--
 src/linkahead/apiutils.py                 |   6 +-
 src/linkahead/common/models.py            |  22 ++--
 unittests/test_entity.py                  | 126 +++++++++++-----------
 5 files changed, 89 insertions(+), 80 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1fd615a..90fd8f11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * New setup extra `test` which installs the dependencies for testing.
 
 ### Changed ###
+* Renamed the `filter` function of Container, ParentList and PropertyList to `filter_by_identity`.
 
 ### Deprecated ###
 
diff --git a/src/doc/tutorials/complex_data_models.rst b/src/doc/tutorials/complex_data_models.rst
index 168cf3b9..873c8bd5 100644
--- a/src/doc/tutorials/complex_data_models.rst
+++ b/src/doc/tutorials/complex_data_models.rst
@@ -100,29 +100,29 @@ entities. A short example:
    properties = r.properties
 
    # As r only has one property with id 101, this returns a list containing only p1_1
-   properties.filter(pid=101)
+   properties.filter_by_identity(pid=101)
    # Result: [p1_1]
 
    # Filtering with name="Property 1" returns both p1_1 and p1_2, as they share their name
-   properties.filter(name="Property 1")
+   properties.filter_by_identity(name="Property 1")
    # Result: [p1_1, p1_2]
 
    #  If both name and pid are given, matching is based only on pid for all entities that have an id
-   properties.filter(pid="102", name="Other Property")
+   properties.filter_by_identity(pid="102", name="Other Property")
    # Result: [p2_1, p2_2, p2_3]
 
-   # However, filtering with name="Property 1" and id=101 returns both p1_1 and p1_2, because
+   # However, filter_by_identity with name="Property 1" and id=101 returns both p1_1 and p1_2, because
    # p1_2 does not have an id and matches the name
-   properties.filter(pid="101", name="Property 1")
+   properties.filter_by_identity(pid="101", name="Property 1")
    # Result: [p1_1, p1_2]
 
    # We can also filter using an entity, in which case the name and id of the entity are used:
-   properties.filter(pid="102", name="Property 2") == properties.filter(p2_1)
+   properties.filter_by_identity(pid="102", name="Property 2") == properties.filter_by_identity(p2_1)
    # Result: True
 
    # If we only need properties that match both id and name, we can set the parameter
    # conjunction to True:
-   properties.filter(pid="102", name="Property 2", conjunction=True)
+   properties.filter_by_identity(pid="102", name="Property 2", conjunction=True)
    # Result: [p2_1]
 
 The filter function of ParentList works analogously.
diff --git a/src/linkahead/apiutils.py b/src/linkahead/apiutils.py
index 1aa127d3..b2a612fa 100644
--- a/src/linkahead/apiutils.py
+++ b/src/linkahead/apiutils.py
@@ -386,7 +386,7 @@ def compare_entities(entity0: Optional[Entity] = None,
     for prop in entity0.properties:
         # ToDo: Would making id default break anything?
         key = prop.name if prop.name is not None else prop.id
-        matching = entity1.properties.filter(prop)
+        matching = entity1.properties.filter_by_identity(prop)
         if len(matching) == 0:
             # entity1 has prop, entity0 does not
             diff[0]["properties"][key] = {}
@@ -440,7 +440,7 @@ def compare_entities(entity0: Optional[Entity] = None,
     for prop in entity1.properties:
         key = prop.name if prop.name is not None else prop.id
         # check how often the property appears in entity0
-        num_prop_in_ent0 = len(entity0.properties.filter(prop))
+        num_prop_in_ent0 = len(entity0.properties.filter_by_identity(prop))
         if num_prop_in_ent0 == 0:
             # property is only present in entity0 - add to diff
             diff[1]["properties"][key] = {}
@@ -455,7 +455,7 @@ def compare_entities(entity0: Optional[Entity] = None,
                                          (1, entity1.parents, entity0)]:
         for parent in parents:
             key = parent.name if parent.name is not None else parent.id
-            matching = other_entity.parents.filter(parent)
+            matching = other_entity.parents.filter_by_identity(parent)
             if len(matching) == 0:
                 diff[index]["parents"].append(key)
                 continue
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index 1caa6a4d..526a6f43 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -2562,7 +2562,11 @@ class PropertyList(list):
 
         return xml2str(xml)
 
-    def filter(self, prop: Optional[Property] = None,
+    def filter(self, *args, **kwargs):
+        warnings.warn(DeprecationWarning("This function was renamed to filter_by_identity."))
+        return self.filter(*args, **kwargs)
+
+    def filter_by_identity(self, prop: Optional[Property] = None,
                pid: Union[None, str, int] = None,
                name: Optional[str] = None,
                conjunction: bool = False) -> list:
@@ -2570,7 +2574,7 @@ class PropertyList(list):
         Return all Properties from the given PropertyList that match the
         selection criteria.
 
-        Please refer to the documentation of _filter_entity_list for a detailed
+        Please refer to the documentation of _filter_entity_list_by_identity for a detailed
         description of behaviour.
 
         Params
@@ -2593,7 +2597,7 @@ class PropertyList(list):
         matches          : list
                            List containing all matching Properties
         """
-        return _filter_entity_list(self, pid=pid, name=name, entity=prop,
+        return _filter_entity_list_by_identity(self, pid=pid, name=name, entity=prop,
                                    conjunction=conjunction)
 
     def _get_entity_by_cuid(self, cuid: str):
@@ -2731,7 +2735,11 @@ class ParentList(list):
 
         return xml2str(xml)
 
-    def filter(self, parent: Optional[Parent] = None,
+    def filter(self, *args, **kwargs):
+        warnings.warn(DeprecationWarning("This function was renamed to filter_by_identity."))
+        return self.filter(*args, **kwargs)
+
+    def filter_by_identity(self, parent: Optional[Parent] = None,
                pid: Union[None, str, int] = None,
                name: Optional[str] = None,
                conjunction: bool = False) -> list:
@@ -2739,7 +2747,7 @@ class ParentList(list):
         Return all Parents from the given ParentList that match the selection
         criteria.
 
-        Please refer to the documentation of _filter_entity_list for a detailed
+        Please refer to the documentation of _filter_entity_list_by_identity for a detailed
         description of behaviour.
 
         Params
@@ -2762,7 +2770,7 @@ class ParentList(list):
         matches          : list
                            List containing all matching Parents
         """
-        return _filter_entity_list(self, pid=pid, name=name, entity=parent,
+        return _filter_entity_list_by_identity(self, pid=pid, name=name, entity=parent,
                                    conjunction=conjunction)
 
     def remove(self, parent: Union[Entity, int, str]):
@@ -5537,7 +5545,7 @@ def delete(ids: Union[list[int], range], raise_exception_on_error: bool = True):
     return c.delete(raise_exception_on_error=raise_exception_on_error)
 
 
-def _filter_entity_list(listobject: list[Entity],
+def _filter_entity_list_by_identity(listobject: list[Entity],
                         entity: Optional[Entity] = None,
                         pid: Union[None, str, int] = None,
                         name: Optional[str] = None,
diff --git a/unittests/test_entity.py b/unittests/test_entity.py
index 2127ce02..e946fd40 100644
--- a/unittests/test_entity.py
+++ b/unittests/test_entity.py
@@ -161,7 +161,7 @@ def test_property_list():
     pl.append(p3)
 
 
-def test_filter():
+def test_filter_by_identity():
     rt1 = RecordType(id=100)
     rt2 = RecordType(id=101, name="RT")
     rt3 = RecordType(name="")
@@ -184,7 +184,7 @@ def test_filter():
         for coll in [entity.properties, entity.parents]:
             for ent in test_ents:
                 assert ent not in coll
-                assert ent not in coll.filter(ent)
+                assert ent not in coll.filter_by_identity(ent)
 
         # Checks with each type
         t, t_props, t_pars = entity, entity.properties, entity.parents
@@ -194,23 +194,23 @@ def test_filter():
         tp1 = t.properties[-1]
         t.add_property(p3)
         tp3 = t.properties[-1]
-        assert len(t_props.filter(pid=100)) == 1
-        assert tp1 in t_props.filter(pid=100)
-        assert len(t_props.filter(pid="100")) == 1
-        assert tp1 in t_props.filter(pid="100")
-        assert len(t_props.filter(pid=101, name="RT")) == 1
-        assert tp3 in t_props.filter(pid=101, name="RT")
+        assert len(t_props.filter_by_identity(pid=100)) == 1
+        assert tp1 in t_props.filter_by_identity(pid=100)
+        assert len(t_props.filter_by_identity(pid="100")) == 1
+        assert tp1 in t_props.filter_by_identity(pid="100")
+        assert len(t_props.filter_by_identity(pid=101, name="RT")) == 1
+        assert tp3 in t_props.filter_by_identity(pid=101, name="RT")
         for entity in [rt1, p2, r1, r2]:
-            assert entity not in t_props.filter(pid=100)
-            assert tp1 in t_props.filter(entity)
+            assert entity not in t_props.filter_by_identity(pid=100)
+            assert tp1 in t_props.filter_by_identity(entity)
         # Check that direct addition (not wrapped) works
         t_props.append(p2)
         tp2 = t_props[-1]
-        assert tp2 in t_props.filter(pid=100)
-        assert tp2 not in t_props.filter(pid=101, name="RT")
+        assert tp2 in t_props.filter_by_identity(pid=100)
+        assert tp2 not in t_props.filter_by_identity(pid=101, name="RT")
         for entity in [rt1, r1, r2]:
-            assert entity not in t_props.filter(pid=100)
-            assert tp2 in t_props.filter(entity)
+            assert entity not in t_props.filter_by_identity(pid=100)
+            assert tp2 in t_props.filter_by_identity(entity)
 
         # Parents
         # Filtering with both name and id
@@ -218,67 +218,67 @@ def test_filter():
         tr3 = t.parents[-1]
         t.add_parent(r5)
         tr5 = t.parents[-1]
-        assert tr3 in t_pars.filter(pid=101)
-        assert tr5 not in t_pars.filter(pid=101)
-        assert tr3 not in t_pars.filter(name="R")
-        assert tr5 in t_pars.filter(name="R")
-        assert tr3 in t_pars.filter(pid=101, name="R")
-        assert tr5 not in t_pars.filter(pid=101, name="R")
-        assert tr3 not in t_pars.filter(pid=104, name="RT")
-        assert tr5 in t_pars.filter(pid=104, name="RT")
-        assert tr3 not in t_pars.filter(pid=105, name="T")
-        assert tr5 not in t_pars.filter(pid=105, name="T")
+        assert tr3 in t_pars.filter_by_identity(pid=101)
+        assert tr5 not in t_pars.filter_by_identity(pid=101)
+        assert tr3 not in t_pars.filter_by_identity(name="R")
+        assert tr5 in t_pars.filter_by_identity(name="R")
+        assert tr3 in t_pars.filter_by_identity(pid=101, name="R")
+        assert tr5 not in t_pars.filter_by_identity(pid=101, name="R")
+        assert tr3 not in t_pars.filter_by_identity(pid=104, name="RT")
+        assert tr5 in t_pars.filter_by_identity(pid=104, name="RT")
+        assert tr3 not in t_pars.filter_by_identity(pid=105, name="T")
+        assert tr5 not in t_pars.filter_by_identity(pid=105, name="T")
         # Works also without id / name and with duplicate parents
         for ent in test_ents:
             t.add_parent(ent)
         for ent in t_pars:
-            assert ent in t_pars.filter(ent)
+            assert ent in t_pars.filter_by_identity(ent)
 
     # Grid-Based
     r7 = Record()
     r7.add_property(Property()).add_property(name="A").add_property(name="B")
     r7.add_property(id=27).add_property(id=27, name="A").add_property(id=27, name="B")
     r7.add_property(id=43).add_property(id=43, name="A").add_property(id=43, name="B")
-    assert len(r7.properties.filter(pid=27)) == 3
-    assert len(r7.properties.filter(pid=43)) == 3
-    assert len(r7.properties.filter(pid=43, conjunction=True)) == 3
-    assert len(r7.properties.filter(name="A")) == 3
-    assert len(r7.properties.filter(name="B")) == 3
-    assert len(r7.properties.filter(name="B", conjunction=True)) == 3
-    assert len(r7.properties.filter(pid=1, name="A")) == 1
-    assert len(r7.properties.filter(pid=1, name="A", conjunction=True)) == 0
-    assert len(r7.properties.filter(pid=27, name="B")) == 4
-    assert len(r7.properties.filter(pid=27, name="B", conjunction=True)) == 1
-    assert len(r7.properties.filter(pid=27, name="C")) == 3
-    assert len(r7.properties.filter(pid=27, name="C", conjunction=True)) == 0
+    assert len(r7.properties.filter_by_identity(pid=27)) == 3
+    assert len(r7.properties.filter_by_identity(pid=43)) == 3
+    assert len(r7.properties.filter_by_identity(pid=43, conjunction=True)) == 3
+    assert len(r7.properties.filter_by_identity(name="A")) == 3
+    assert len(r7.properties.filter_by_identity(name="B")) == 3
+    assert len(r7.properties.filter_by_identity(name="B", conjunction=True)) == 3
+    assert len(r7.properties.filter_by_identity(pid=1, name="A")) == 1
+    assert len(r7.properties.filter_by_identity(pid=1, name="A", conjunction=True)) == 0
+    assert len(r7.properties.filter_by_identity(pid=27, name="B")) == 4
+    assert len(r7.properties.filter_by_identity(pid=27, name="B", conjunction=True)) == 1
+    assert len(r7.properties.filter_by_identity(pid=27, name="C")) == 3
+    assert len(r7.properties.filter_by_identity(pid=27, name="C", conjunction=True)) == 0
     # Entity based filtering behaves the same
-    assert (r7.properties.filter(pid=27) ==
-            r7.properties.filter(Property(id=27)))
-    assert (r7.properties.filter(pid=43, conjunction=True) ==
-            r7.properties.filter(Property(id=43), conjunction=True))
-    assert (r7.properties.filter(name="A") ==
-            r7.properties.filter(Property(name="A")))
-    assert (r7.properties.filter(name="B") ==
-            r7.properties.filter(Property(name="B")))
-    assert (r7.properties.filter(name="B", conjunction=True) ==
-            r7.properties.filter(Property(name="B"), conjunction=True))
-    assert (r7.properties.filter(pid=1, name="A") ==
-            r7.properties.filter(Property(id=1, name="A")))
-    assert (r7.properties.filter(pid=1, name="A", conjunction=True) ==
-            r7.properties.filter(Property(id=1, name="A"), conjunction=True))
-    assert (r7.properties.filter(pid=27, name="B") ==
-            r7.properties.filter(Property(id=27, name="B")))
-    assert (r7.properties.filter(pid=27, name="B", conjunction=True) ==
-            r7.properties.filter(Property(id=27, name="B"), conjunction=True))
-    assert (r7.properties.filter(pid=27, name="C") ==
-            r7.properties.filter(Property(id=27, name="C")))
-    assert (r7.properties.filter(pid=27, name="C", conjunction=True) ==
-            r7.properties.filter(Property(id=27, name="C"), conjunction=True))
+    assert (r7.properties.filter_by_identity(pid=27) ==
+            r7.properties.filter_by_identity(Property(id=27)))
+    assert (r7.properties.filter_by_identity(pid=43, conjunction=True) ==
+            r7.properties.filter_by_identity(Property(id=43), conjunction=True))
+    assert (r7.properties.filter_by_identity(name="A") ==
+            r7.properties.filter_by_identity(Property(name="A")))
+    assert (r7.properties.filter_by_identity(name="B") ==
+            r7.properties.filter_by_identity(Property(name="B")))
+    assert (r7.properties.filter_by_identity(name="B", conjunction=True) ==
+            r7.properties.filter_by_identity(Property(name="B"), conjunction=True))
+    assert (r7.properties.filter_by_identity(pid=1, name="A") ==
+            r7.properties.filter_by_identity(Property(id=1, name="A")))
+    assert (r7.properties.filter_by_identity(pid=1, name="A", conjunction=True) ==
+            r7.properties.filter_by_identity(Property(id=1, name="A"), conjunction=True))
+    assert (r7.properties.filter_by_identity(pid=27, name="B") ==
+            r7.properties.filter_by_identity(Property(id=27, name="B")))
+    assert (r7.properties.filter_by_identity(pid=27, name="B", conjunction=True) ==
+            r7.properties.filter_by_identity(Property(id=27, name="B"), conjunction=True))
+    assert (r7.properties.filter_by_identity(pid=27, name="C") ==
+            r7.properties.filter_by_identity(Property(id=27, name="C")))
+    assert (r7.properties.filter_by_identity(pid=27, name="C", conjunction=True) ==
+            r7.properties.filter_by_identity(Property(id=27, name="C"), conjunction=True))
     # Name only matching and name overwrite
     r8 = Record().add_property(name="A").add_property(name="B").add_property(name="B")
     r8.add_property(Property(name="A"), name="B")
     r8.add_property(Property(name="A", id=12), name="C")
-    assert len(r8.properties.filter(name="A")) == 1
-    assert len(r8.properties.filter(name="B")) == 3
-    assert len(r8.properties.filter(name="C")) == 1
-    assert len(r8.properties.filter(pid=12)) == 1
+    assert len(r8.properties.filter_by_identity(name="A")) == 1
+    assert len(r8.properties.filter_by_identity(name="B")) == 3
+    assert len(r8.properties.filter_by_identity(name="C")) == 1
+    assert len(r8.properties.filter_by_identity(pid=12)) == 1
-- 
GitLab


From e0554c5e740cdd9c9d29a1ca4e689d1630fe0ec3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 10 Jan 2025 09:30:19 +0100
Subject: [PATCH 2/3] MAINT: rename the filter function of Container

---
 src/doc/tutorials/complex_data_models.rst |  2 +-
 src/linkahead/common/models.py            | 10 +++++-----
 unittests/test_container.py               |  5 +++--
 3 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/doc/tutorials/complex_data_models.rst b/src/doc/tutorials/complex_data_models.rst
index d418298a..52757c32 100644
--- a/src/doc/tutorials/complex_data_models.rst
+++ b/src/doc/tutorials/complex_data_models.rst
@@ -140,5 +140,5 @@ A short example:
    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")
+   c.filter_by_identity(name="Property 1")
    # Result: [p1]
diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index 0fc669ce..c83354f8 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -3736,21 +3736,21 @@ class Container(list):
 
         return sync_dict
 
-    def filter(self, entity: Optional[Entity] = None,
-               pid: Union[None, str, int] = None,
+    def filter_by_identity(self, entity: Optional[Entity] = None,
+               entity_id: 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
+        Please refer to the documentation of _filter_entity_list_by_identity for a detailed
         description of behaviour.
 
         Params
         ------
         entity            : Entity
                             Entity to match name and ID with
-        pid               : str, int
+        entity_id         : str, int
                             Parent ID to match
         name              : str
                             Parent name to match
@@ -3764,7 +3764,7 @@ class Container(list):
         matches          : list
                            List containing all matching Entities
         """
-        return _filter_entity_list(self, pid=pid, name=name, entity=entity,
+        return _filter_entity_list_by_identity(self, pid=entity_id, name=name, entity=entity,
                                    conjunction=conjunction)
     @staticmethod
     def _find_dependencies_in_container(container: Container):
diff --git a/unittests/test_container.py b/unittests/test_container.py
index 4ef85910..70498fd9 100644
--- a/unittests/test_container.py
+++ b/unittests/test_container.py
@@ -201,10 +201,11 @@ def test_container_slicing():
         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
+    # this is a very rudimentary test since filter_by_identity is based on
+    # _filter_entity_list_by_identity 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")
+    recs = cont.filter_by_identity(name="TestRec2")
     assert len(recs)==1
     recs[0].name =="TestRec2"
-- 
GitLab


From 71f51dd30ad8cfabaf78db805ecc49c2978b40af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20tom=20W=C3=B6rden?= <h.tomwoerden@indiscale.com>
Date: Fri, 10 Jan 2025 12:46:21 +0100
Subject: [PATCH 3/3] TST: add unittest for deprecation warning

---
 src/linkahead/common/models.py |  4 ++--
 unittests/test_entity.py       | 14 ++++++++++++++
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py
index c83354f8..18508d5a 100644
--- a/src/linkahead/common/models.py
+++ b/src/linkahead/common/models.py
@@ -2564,7 +2564,7 @@ class PropertyList(list):
 
     def filter(self, *args, **kwargs):
         warnings.warn(DeprecationWarning("This function was renamed to filter_by_identity."))
-        return self.filter(*args, **kwargs)
+        return self.filter_by_identity(*args, **kwargs)
 
     def filter_by_identity(self, prop: Optional[Property] = None,
                pid: Union[None, str, int] = None,
@@ -2735,7 +2735,7 @@ class ParentList(list):
 
     def filter(self, *args, **kwargs):
         warnings.warn(DeprecationWarning("This function was renamed to filter_by_identity."))
-        return self.filter(*args, **kwargs)
+        return self.filter_by_identity(*args, **kwargs)
 
     def filter_by_identity(self, parent: Optional[Parent] = None,
                pid: Union[None, str, int] = None,
diff --git a/unittests/test_entity.py b/unittests/test_entity.py
index e946fd40..da057783 100644
--- a/unittests/test_entity.py
+++ b/unittests/test_entity.py
@@ -29,6 +29,7 @@ import unittest
 import linkahead
 from linkahead import (INTEGER, Entity, Parent, Property, Record, RecordType,
                        configure_connection)
+import warnings
 from linkahead.common.models import SPECIAL_ATTRIBUTES
 from linkahead.connection.mockup import MockUpServerConnection
 from lxml import etree
@@ -282,3 +283,16 @@ def test_filter_by_identity():
     assert len(r8.properties.filter_by_identity(name="B")) == 3
     assert len(r8.properties.filter_by_identity(name="C")) == 1
     assert len(r8.properties.filter_by_identity(pid=12)) == 1
+
+
+    with warnings.catch_warnings(record=True) as w:
+        # Cause all warnings to always be triggered.
+        warnings.simplefilter("always")
+
+        r7.properties.filter(pid=34)
+        assert issubclass(w[-1].category, DeprecationWarning)
+        assert "This function was renamed" in str(w[-1].message)
+
+        t.parents.filter(pid=234)
+        assert issubclass(w[-1].category, DeprecationWarning)
+        assert "This function was renamed" in str(w[-1].message)
-- 
GitLab