From 1ff36c761d7ef3a70979573bdfea666831b0fe3c Mon Sep 17 00:00:00 2001 From: Leonardo Schwarz Date: Mon, 5 Aug 2024 15:57:32 +0200 Subject: [PATCH] allow passing method through Bfabric.save so checkandinsert endpoint can be used, fixes #98 --- bfabric/bfabric.py | 6 ++++-- bfabric/engine/engine_suds.py | 6 ++++-- bfabric/engine/engine_zeep.py | 6 ++++-- bfabric/tests/unit/test_bfabric.py | 8 ++++++-- docs/changelog.md | 1 + 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/bfabric/bfabric.py b/bfabric/bfabric.py index 1f8838f7..d0be4b1a 100755 --- a/bfabric/bfabric.py +++ b/bfabric/bfabric.py @@ -183,14 +183,16 @@ def read( result.assert_success() return result.get_first_n_results(max_results) - def save(self, endpoint: str, obj: dict[str, Any], check: bool = True) -> ResultContainer: + def save(self, endpoint: str, obj: dict[str, Any], check: bool = True, method: str = "save") -> ResultContainer: """Saves the provided object to the specified endpoint. :param endpoint: the endpoint to save to, e.g. "sample" :param obj: the object to save :param check: whether to raise an error if the response is not successful + :param method: the method to use for saving, generally "save", but in some cases e.g. "checkandinsert" is more + appropriate to be used instead. :return a ResultContainer describing the saved object if successful """ - results = self.engine.save(endpoint=endpoint, obj=obj, auth=self.auth) + results = self.engine.save(endpoint=endpoint, obj=obj, auth=self.auth, method=method) if check: results.assert_success() return results diff --git a/bfabric/engine/engine_suds.py b/bfabric/engine/engine_suds.py index 85bd0782..a881de4a 100644 --- a/bfabric/engine/engine_suds.py +++ b/bfabric/engine/engine_suds.py @@ -50,16 +50,18 @@ def read( response = service.read(full_query) return self._convert_results(response=response, endpoint=endpoint) - def save(self, endpoint: str, obj: dict, auth: BfabricAuth) -> ResultContainer: + def save(self, endpoint: str, obj: dict, auth: BfabricAuth, method: str = "save") -> ResultContainer: """Saves the provided object to the specified endpoint. :param endpoint: the endpoint to save to, e.g. "sample" :param obj: the object to save :param auth: the authentication handle of the user performing the request + :param method: the method to use for saving, generally "save", but in some cases e.g. "checkandinsert" is more + appropriate to be used instead. """ query = {"login": auth.login, "password": auth.password, endpoint: obj} service = self._get_suds_service(endpoint) try: - response = service.save(query) + response = getattr(service, method)(query) except MethodNotFound as e: raise BfabricRequestError(f"SUDS failed to find save method for the {endpoint} endpoint.") from e return self._convert_results(response=response, endpoint=endpoint) diff --git a/bfabric/engine/engine_zeep.py b/bfabric/engine/engine_zeep.py index 08a367de..6ad7a80f 100644 --- a/bfabric/engine/engine_zeep.py +++ b/bfabric/engine/engine_zeep.py @@ -62,11 +62,13 @@ def read( response = client.service.read(full_query) return self._convert_results(response=response, endpoint=endpoint) - def save(self, endpoint: str, obj: dict, auth: BfabricAuth) -> ResultContainer: + def save(self, endpoint: str, obj: dict, auth: BfabricAuth, method: str = "save") -> ResultContainer: """Saves the provided object to the specified endpoint. :param endpoint: the endpoint to save to, e.g. "sample" :param obj: the object to save :param auth: the authentication handle of the user performing the request + :param method: the method to use for saving, generally "save", but in some cases e.g. "checkandinsert" is more + appropriate to be used instead. """ query = copy.deepcopy(obj) @@ -81,7 +83,7 @@ def save(self, endpoint: str, obj: dict, auth: BfabricAuth) -> ResultContainer: try: with client.settings(strict=False): - response = client.service.save(full_query) + response = getattr(client.service, method)(full_query) except AttributeError as e: if e.args[0] == "Service has no operation 'save'": raise BfabricRequestError(f"ZEEP failed to find save method for the {endpoint} endpoint.") from e diff --git a/bfabric/tests/unit/test_bfabric.py b/bfabric/tests/unit/test_bfabric.py index e75a9de0..8e30c043 100644 --- a/bfabric/tests/unit/test_bfabric.py +++ b/bfabric/tests/unit/test_bfabric.py @@ -225,7 +225,9 @@ def test_save_when_auth_and_check_false(bfabric_instance, mocker): assert result == mock_engine.save.return_value method_assert_success.assert_not_called() - mock_engine.save.assert_called_once_with(endpoint="test_endpoint", obj={"key": "value"}, auth=mock_auth) + mock_engine.save.assert_called_once_with( + endpoint="test_endpoint", obj={"key": "value"}, auth=mock_auth, method="save" + ) def test_save_when_auth_and_check_true(bfabric_instance, mocker): @@ -240,7 +242,9 @@ def test_save_when_auth_and_check_true(bfabric_instance, mocker): assert result == mock_engine.save.return_value method_assert_success.assert_called_once() - mock_engine.save.assert_called_once_with(endpoint="test_endpoint", obj={"key": "value"}, auth=mock_auth) + mock_engine.save.assert_called_once_with( + endpoint="test_endpoint", obj={"key": "value"}, auth=mock_auth, method="save" + ) def test_delete_when_no_auth(bfabric_instance, mocker): diff --git a/docs/changelog.md b/docs/changelog.md index a8511c2d..23ffefb7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -15,6 +15,7 @@ Versioning currently follows `X.Y.Z` where - Add `Workunit`, `Parameter`, and `Resource` entities. - Add concept of has_many and has_one relationships to entities. - `bfabric_slurm_queue_status.py` to quickly check slurm queue status. +- `Bfabric.save` provides `method` which can be set to `checkandinsert` for specific use cases. ### Changed