diff --git a/doc_template/source/conf.py b/doc_template/source/conf.py index 230d761..16aa411 100644 --- a/doc_template/source/conf.py +++ b/doc_template/source/conf.py @@ -1,4 +1,5 @@ """Configuration file for the Sphinx documentation builder.""" + # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html diff --git a/src/aind_codeocean_api/__init__.py b/src/aind_codeocean_api/__init__.py index dc06f2a..4126d57 100644 --- a/src/aind_codeocean_api/__init__.py +++ b/src/aind_codeocean_api/__init__.py @@ -1,2 +1,3 @@ """Python wrapper of CodeOcean's REST API""" + __version__ = "0.4.1" diff --git a/src/aind_codeocean_api/codeocean.py b/src/aind_codeocean_api/codeocean.py index 35e0e0d..761d6a8 100644 --- a/src/aind_codeocean_api/codeocean.py +++ b/src/aind_codeocean_api/codeocean.py @@ -1,5 +1,6 @@ """Module to interface with Code Ocean's backend. """ + import json import logging from enum import Enum @@ -23,6 +24,7 @@ class CodeOceanClient: class _URLStrings(Enum): """Enum class for CodeOcean's url strings""" + ARCHIVE = "archive" CAPSULES = "capsules" COMPUTATIONS = "computations" DATA_ASSETS = "data_assets" @@ -553,3 +555,51 @@ def update_permissions( ) response = requests.post(url, json=permissions, auth=(self.token, "")) return response + + def archive_data_asset( + self, data_asset_id: str, archive: bool = True + ) -> requests.models.Response: + """ + This will archive or unarchive a data asset using a PATCH request to + the Code Ocean API. + + Parameters + --------------- + data_asset_id : string + ID of the data asset + + Returns + --------------- + requests.models.Response + """ + + url = ( + f"{self.asset_url}/{data_asset_id}/" + f"{self._URLStrings.ARCHIVE.value}" + ) + response = requests.patch( + url, params={"archive": archive}, auth=(self.token, "") + ) + return response + + def delete_data_asset( + self, data_asset_id: str + ) -> requests.models.Response: + """ + This will delete a data asset using a DELETE request to the Code Ocean + API. + + Parameters + --------------- + data_asset_id : string + ID of the data asset + + Returns + --------------- + requests.models.Response + """ + + url = f"{self.asset_url}/{data_asset_id}" + + response = requests.delete(url, auth=(self.token, "")) + return response diff --git a/src/aind_codeocean_api/credentials.py b/src/aind_codeocean_api/credentials.py index f0a90c5..dd8fbb7 100644 --- a/src/aind_codeocean_api/credentials.py +++ b/src/aind_codeocean_api/credentials.py @@ -1,4 +1,5 @@ """Basic CodeOcean Credentials Handling.""" + import functools import json import os diff --git a/tests/test_codeocean_requests.py b/tests/test_codeocean_requests.py index 8e1ac10..112d247 100644 --- a/tests/test_codeocean_requests.py +++ b/tests/test_codeocean_requests.py @@ -1,4 +1,5 @@ """Tests CodeOcean API python interface""" + import json import unittest from typing import Any, Callable, List @@ -85,11 +86,29 @@ def request_put_response(url: str, json: dict) -> MockResponse: status_code=200, content=success_message, url=url ) + def request_patch_response(url: str) -> MockResponse: + """Mock a patch response""" + success_message = map_input_to_success_message(url) + return MockResponse( + status_code=202, content=success_message, url=url + ) + + def request_delete_response(url: str) -> MockResponse: + """Mock a delete response""" + success_message = map_input_to_success_message(url) + return MockResponse( + status_code=204, content=success_message, url=url + ) + # TODO: Change these to enums if req_type == "post": return request_post_response elif req_type == "get": return request_get_response + elif req_type == "patch": + return request_patch_response + elif req_type == "delete": + return request_delete_response else: return request_put_response @@ -990,6 +1009,61 @@ def request_post_response(json: dict) -> MockResponse: ) self.assertEqual(response.status_code, 204) + @mock.patch("requests.patch") + def test_archive_data_asset( + self, mock_api_patch: unittest.mock.MagicMock + ) -> None: + """Tests the response of archiving a data asset""" + + def map_to_success_message(_) -> dict: + """Map to a success message""" + return "" + + mocked_success_patch = self.mock_success_response( + map_to_success_message, req_type="patch" + ) + + example_data_asset_id = "da8dd108-2a10-471d-82b9-1e671b107bf8" + expected_url = ( + f"{self.co_client.asset_url}/" + "{example_data_asset_id}/archive?archive=True" + ) + + mock_api_patch.return_value = mocked_success_patch(url=expected_url) + + response = self.co_client.archive_data_asset( + data_asset_id=example_data_asset_id, archive=True + ) + + self.assertEqual(response.url, expected_url) + self.assertEqual(response.status_code, 202) + + @mock.patch("requests.delete") + def test_delete_data_asset( + self, mock_api_delete: unittest.mock.MagicMock + ) -> None: + """Tests the response of deleting a data asset""" + + def map_to_success_message(_) -> dict: + """Map to a success message""" + return "" + + mocked_success_delete = self.mock_success_response( + map_to_success_message, req_type="delete" + ) + + example_data_asset_id = "da8dd108-2a10-471d-82b9-1e671b107bf8" + expected_url = f"{self.co_client.asset_url}/{example_data_asset_id}" + + mock_api_delete.return_value = mocked_success_delete(url=expected_url) + + response = self.co_client.delete_data_asset( + data_asset_id=example_data_asset_id + ) + + self.assertEqual(response.url, expected_url) + self.assertEqual(response.status_code, 204) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_credentials.py b/tests/test_credentials.py index 741a203..cb02484 100644 --- a/tests/test_credentials.py +++ b/tests/test_credentials.py @@ -1,4 +1,5 @@ """Tests credentials loader.""" + import json import os import unittest