diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e2a2501a9ad3c61baea00717c7306f1c35af036..e2c5cd7fa67e180a86800f99c96eaf815031473a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### +* [#104](https://gitlab.com/linkahead/linkahead-pylib/-/issues/104) Selecting + parts of a `Container` with a `slice` used to return a `list` object instead + of a `Container`, removing all useful methods of the `Container` class. This + has been fixed and using a `slice` such as `[:2]` now returns a new + `Container`. + ### Security ### ### Documentation ### diff --git a/src/linkahead/common/models.py b/src/linkahead/common/models.py index ea537ffe8c44a7a7fb79c2d4080b63f9b3da2284..031afe4e514908e81e5980d14244dec7390cf86c 100644 --- a/src/linkahead/common/models.py +++ b/src/linkahead/common/models.py @@ -4,9 +4,10 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen -# Copyright (C) 2020-2023 Indiscale GmbH <info@indiscale.com> +# Copyright (C) 2020-2024 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2020-2023 Florian Spreckelsen <f.spreckelsen@indiscale.com> # Copyright (C) 2020-2022 Timm Fitschen <t.fitschen@indiscale.com> +# Copyright (C) 2024 Joscha Schmiedt <joscha@schmiedt.dev> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -3001,6 +3002,14 @@ class Container(list): def __repr__(self): return xml2str(self.to_xml()) + def __getitem__(self, key): + self_as_list_slice = super().__getitem__(key) + if isinstance(self_as_list_slice, list): + # Construct new Container from list slice + return Container().extend(self_as_list_slice) + else: + return self_as_list_slice + @staticmethod def from_xml(xml_str): """Creates a Container from the given xml string. diff --git a/tox.ini b/tox.ini index 570324d4cc91222ecb619249bc71ec0b58f5c4e4..5282b0782bea1bc9515b9362e3ef2021f3f9cd11 100644 --- a/tox.ini +++ b/tox.ini @@ -18,3 +18,5 @@ max-line-length=100 testpaths = unittests xfail_strict = True addopts = -x -vv --cov=caosdb +pythonpath = src + diff --git a/unittests/test_container.py b/unittests/test_container.py index 4cd8fefcaefee9fe6fdc5857805353227b493dfb..c3a60140d43383c81f03c38c9dd5cc7779bc77ba 100644 --- a/unittests/test_container.py +++ b/unittests/test_container.py @@ -5,7 +5,8 @@ # This file is a part of the LinkAhead Project. # # Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> -# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2024 Joscha Schmiedt <joscha@schmiedt.dev> +# Copyright (C) 2020-2024 IndiScale GmbH <info@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -178,3 +179,23 @@ def test_container_deletion_with_references(): assert len(deps14a) == 1 and deps14a.pop() == -1 assert len(deps14b) == 1 and deps14b.pop() == -1 assert len(deps15) == 1 and deps15.pop() == -1 + + +def test_container_slicing(): + cont = db.Container() + cont.extend([db.Record(name=f"TestRec{ii+1}") for ii in range(5)]) + assert isinstance(cont, db.common.models.Container) + container_slice = cont[:2] + assert isinstance(container_slice, db.common.models.Container), \ + f"Container slice should be Container, was {type(container_slice)}" + for element in container_slice: + assert isinstance(element, db.Record), \ + f"element in slice was not Record, but {type(element)}" + assert len(container_slice) == 2 + assert cont[-1].name == "TestRec5" + + with pytest.raises(TypeError): + cont["stringkey"] + + with pytest.raises(TypeError): + cont[[0, 2, 3]]