diff --git a/CHANGELOG.md b/CHANGELOG.md index e1fd615a09ae8023f21bebe404a99c70951bb5c3..8fe5c3ac41da7eb3c1e1698ea9c2c259de789846 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/doc/tutorials/complex_data_models.rst b/src/doc/tutorials/complex_data_models.rst index 168cf3b9f0d6839ed8f78beb01ae24fb9d489e88..6c9520c94105e4106343ed2ab1a4c807d669d977 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] diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py index 1caa6a4de14fc6551aa7cfe940c2074be80a1281..031d8058def2866d3a3d4c3b16438fd22f871a5f 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. diff --git a/unittests/test_container.py b/unittests/test_container.py index c3a60140d43383c81f03c38c9dd5cc7779bc77ba..4ef85910fcd2f5328b5208122a8683d4ce3b1ed6 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"