From 2488c17608f530016165317bf57b5fa05c92bf90 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:28:10 +0000 Subject: [PATCH] Restructure ndi.cloud.api.documents to support nested package structure - Created `src/ndi/cloud/api/implementation/__init__.py` to make it a package. - Created `src/ndi/cloud/api/implementation/documents/` directory and `__init__.py`. - Implemented document operations (`add_document`, `get_document`, `update_document`, `delete_document`, `list_dataset_documents`) in `src/ndi/cloud/api/implementation/documents/`. - Created `src/ndi/cloud/api/documents.py` as a module exposing these operations. - Added unit tests in `tests/test_cloud_documents.py`. --- src/ndi/cloud/api/documents.py | 77 +++++++++++++++++++ src/ndi/cloud/api/implementation/__init__.py | 0 .../api/implementation/documents/__init__.py | 0 .../implementation/documents/add_document.py | 47 +++++++++++ .../documents/delete_document.py | 46 +++++++++++ .../implementation/documents/get_document.py | 46 +++++++++++ .../documents/list_dataset_documents.py | 48 ++++++++++++ .../documents/update_document.py | 49 ++++++++++++ tests/test_cloud_documents.py | 71 +++++++++++++++++ 9 files changed, 384 insertions(+) create mode 100644 src/ndi/cloud/api/documents.py create mode 100644 src/ndi/cloud/api/implementation/__init__.py create mode 100644 src/ndi/cloud/api/implementation/documents/__init__.py create mode 100644 src/ndi/cloud/api/implementation/documents/add_document.py create mode 100644 src/ndi/cloud/api/implementation/documents/delete_document.py create mode 100644 src/ndi/cloud/api/implementation/documents/get_document.py create mode 100644 src/ndi/cloud/api/implementation/documents/list_dataset_documents.py create mode 100644 src/ndi/cloud/api/implementation/documents/update_document.py create mode 100644 tests/test_cloud_documents.py diff --git a/src/ndi/cloud/api/documents.py b/src/ndi/cloud/api/documents.py new file mode 100644 index 0000000..be387b3 --- /dev/null +++ b/src/ndi/cloud/api/documents.py @@ -0,0 +1,77 @@ +from .implementation.documents.add_document import AddDocument as AddDocumentImpl +from .implementation.documents.get_document import GetDocument as GetDocumentImpl +from .implementation.documents.update_document import UpdateDocument as UpdateDocumentImpl +from .implementation.documents.delete_document import DeleteDocument as DeleteDocumentImpl +from .implementation.documents.list_dataset_documents import ListDatasetDocuments as ListDatasetDocumentsImpl + +def add_document(dataset_id, document_info): + """ + Adds a document to a dataset. + + Args: + dataset_id (str): The ID of the dataset. + document_info (dict): The document information to add. + + Returns: + tuple: (success, answer, response, url) + """ + api_call = AddDocumentImpl(dataset_id, document_info) + return api_call.execute() + +def get_document(dataset_id, document_id): + """ + Gets a document from a dataset. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + + Returns: + tuple: (success, answer, response, url) + """ + api_call = GetDocumentImpl(dataset_id, document_id) + return api_call.execute() + +def update_document(dataset_id, document_id, document_info): + """ + Updates a document in a dataset. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + document_info (dict): The updated document information. + + Returns: + tuple: (success, answer, response, url) + """ + api_call = UpdateDocumentImpl(dataset_id, document_id, document_info) + return api_call.execute() + +def delete_document(dataset_id, document_id): + """ + Deletes a document from a dataset. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + + Returns: + tuple: (success, answer, response, url) + """ + api_call = DeleteDocumentImpl(dataset_id, document_id) + return api_call.execute() + +def list_dataset_documents(dataset_id, page=1, page_size=20): + """ + Lists documents in a dataset. + + Args: + dataset_id (str): The ID of the dataset. + page (int, optional): The page number. Defaults to 1. + page_size (int, optional): The number of documents per page. Defaults to 20. + + Returns: + tuple: (success, answer, response, url) + """ + api_call = ListDatasetDocumentsImpl(dataset_id, page, page_size) + return api_call.execute() diff --git a/src/ndi/cloud/api/implementation/__init__.py b/src/ndi/cloud/api/implementation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ndi/cloud/api/implementation/documents/__init__.py b/src/ndi/cloud/api/implementation/documents/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ndi/cloud/api/implementation/documents/add_document.py b/src/ndi/cloud/api/implementation/documents/add_document.py new file mode 100644 index 0000000..462bf23 --- /dev/null +++ b/src/ndi/cloud/api/implementation/documents/add_document.py @@ -0,0 +1,47 @@ +from ...call import Call +from ... import url +from ....authenticate import authenticate +import requests +import json + +class AddDocument(Call): + """ + Implementation class for adding a new document to a dataset. + """ + + def __init__(self, dataset_id, document_info): + """ + Creates a new AddDocument API call object. + + Args: + dataset_id (str): The ID of the dataset. + document_info (dict): The document information to add. + """ + self.dataset_id = dataset_id + self.document_info = document_info + self.endpoint_name = 'add_document' + + def execute(self): + """ + Performs the API call to add a document. + """ + token = authenticate() + + api_url = url.get_url(self.endpoint_name, dataset_id=self.dataset_id) + + headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {token}' + } + + response = requests.post(api_url, headers=headers, json=self.document_info) + + if response.status_code in [200, 201]: + return True, response.json(), response, api_url + else: + try: + answer = response.json() + except json.JSONDecodeError: + answer = response.text + return False, answer, response, api_url diff --git a/src/ndi/cloud/api/implementation/documents/delete_document.py b/src/ndi/cloud/api/implementation/documents/delete_document.py new file mode 100644 index 0000000..b617695 --- /dev/null +++ b/src/ndi/cloud/api/implementation/documents/delete_document.py @@ -0,0 +1,46 @@ +from ...call import Call +from ... import url +from ....authenticate import authenticate +import requests +import json + +class DeleteDocument(Call): + """ + Implementation class for deleting a document from a dataset. + """ + + def __init__(self, dataset_id, document_id): + """ + Creates a new DeleteDocument API call object. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + """ + self.dataset_id = dataset_id + self.document_id = document_id + self.endpoint_name = 'delete_document' + + def execute(self): + """ + Performs the API call to delete a document. + """ + token = authenticate() + + api_url = url.get_url(self.endpoint_name, dataset_id=self.dataset_id, document_id=self.document_id) + + headers = { + 'Accept': 'application/json', + 'Authorization': f'Bearer {token}' + } + + response = requests.delete(api_url, headers=headers) + + if response.status_code == 200: + return True, response.json(), response, api_url + else: + try: + answer = response.json() + except json.JSONDecodeError: + answer = response.text + return False, answer, response, api_url diff --git a/src/ndi/cloud/api/implementation/documents/get_document.py b/src/ndi/cloud/api/implementation/documents/get_document.py new file mode 100644 index 0000000..ac37c8b --- /dev/null +++ b/src/ndi/cloud/api/implementation/documents/get_document.py @@ -0,0 +1,46 @@ +from ...call import Call +from ... import url +from ....authenticate import authenticate +import requests +import json + +class GetDocument(Call): + """ + Implementation class for getting a document from a dataset. + """ + + def __init__(self, dataset_id, document_id): + """ + Creates a new GetDocument API call object. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + """ + self.dataset_id = dataset_id + self.document_id = document_id + self.endpoint_name = 'get_document' + + def execute(self): + """ + Performs the API call to get a document. + """ + token = authenticate() + + api_url = url.get_url(self.endpoint_name, dataset_id=self.dataset_id, document_id=self.document_id) + + headers = { + 'Accept': 'application/json', + 'Authorization': f'Bearer {token}' + } + + response = requests.get(api_url, headers=headers) + + if response.status_code == 200: + return True, response.json(), response, api_url + else: + try: + answer = response.json() + except json.JSONDecodeError: + answer = response.text + return False, answer, response, api_url diff --git a/src/ndi/cloud/api/implementation/documents/list_dataset_documents.py b/src/ndi/cloud/api/implementation/documents/list_dataset_documents.py new file mode 100644 index 0000000..1da9db5 --- /dev/null +++ b/src/ndi/cloud/api/implementation/documents/list_dataset_documents.py @@ -0,0 +1,48 @@ +from ...call import Call +from ... import url +from ....authenticate import authenticate +import requests +import json + +class ListDatasetDocuments(Call): + """ + Implementation class for listing documents in a dataset. + """ + + def __init__(self, dataset_id, page=1, page_size=20): + """ + Creates a new ListDatasetDocuments API call object. + + Args: + dataset_id (str): The ID of the dataset. + page (int, optional): The page number. Defaults to 1. + page_size (int, optional): The number of documents per page. Defaults to 20. + """ + self.dataset_id = dataset_id + self.page = page + self.page_size = page_size + self.endpoint_name = 'list_dataset_documents' + + def execute(self): + """ + Performs the API call to list documents. + """ + token = authenticate() + + api_url = url.get_url(self.endpoint_name, dataset_id=self.dataset_id, page=self.page, page_size=self.page_size) + + headers = { + 'Accept': 'application/json', + 'Authorization': f'Bearer {token}' + } + + response = requests.get(api_url, headers=headers) + + if response.status_code == 200: + return True, response.json(), response, api_url + else: + try: + answer = response.json() + except json.JSONDecodeError: + answer = response.text + return False, answer, response, api_url diff --git a/src/ndi/cloud/api/implementation/documents/update_document.py b/src/ndi/cloud/api/implementation/documents/update_document.py new file mode 100644 index 0000000..6e4024c --- /dev/null +++ b/src/ndi/cloud/api/implementation/documents/update_document.py @@ -0,0 +1,49 @@ +from ...call import Call +from ... import url +from ....authenticate import authenticate +import requests +import json + +class UpdateDocument(Call): + """ + Implementation class for updating a document in a dataset. + """ + + def __init__(self, dataset_id, document_id, document_info): + """ + Creates a new UpdateDocument API call object. + + Args: + dataset_id (str): The ID of the dataset. + document_id (str): The ID of the document. + document_info (dict): The updated document information. + """ + self.dataset_id = dataset_id + self.document_id = document_id + self.document_info = document_info + self.endpoint_name = 'update_document' + + def execute(self): + """ + Performs the API call to update a document. + """ + token = authenticate() + + api_url = url.get_url(self.endpoint_name, dataset_id=self.dataset_id, document_id=self.document_id) + + headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {token}' + } + + response = requests.put(api_url, headers=headers, json=self.document_info) + + if response.status_code == 200: + return True, response.json(), response, api_url + else: + try: + answer = response.json() + except json.JSONDecodeError: + answer = response.text + return False, answer, response, api_url diff --git a/tests/test_cloud_documents.py b/tests/test_cloud_documents.py new file mode 100644 index 0000000..96d8bdd --- /dev/null +++ b/tests/test_cloud_documents.py @@ -0,0 +1,71 @@ +import unittest +from unittest.mock import patch, Mock +from ndi.cloud.api.documents import add_document, get_document, update_document, delete_document, list_dataset_documents + +class TestCloudDocuments(unittest.TestCase): + + @patch('ndi.cloud.api.implementation.documents.add_document.authenticate') + @patch('requests.post') + def test_add_document(self, mock_post, mock_authenticate): + mock_authenticate.return_value = 'fake_token' + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {'id': 'doc1'} + mock_post.return_value = mock_response + + success, answer, _, _ = add_document('ds1', {'name': 'doc'}) + self.assertTrue(success) + self.assertEqual(answer['id'], 'doc1') + + @patch('ndi.cloud.api.implementation.documents.get_document.authenticate') + @patch('requests.get') + def test_get_document(self, mock_get, mock_authenticate): + mock_authenticate.return_value = 'fake_token' + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {'id': 'doc1'} + mock_get.return_value = mock_response + + success, answer, _, _ = get_document('ds1', 'doc1') + self.assertTrue(success) + self.assertEqual(answer['id'], 'doc1') + + @patch('ndi.cloud.api.implementation.documents.update_document.authenticate') + @patch('requests.put') + def test_update_document(self, mock_put, mock_authenticate): + mock_authenticate.return_value = 'fake_token' + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {'id': 'doc1'} + mock_put.return_value = mock_response + + success, answer, _, _ = update_document('ds1', 'doc1', {'name': 'new'}) + self.assertTrue(success) + + @patch('ndi.cloud.api.implementation.documents.delete_document.authenticate') + @patch('requests.delete') + def test_delete_document(self, mock_delete, mock_authenticate): + mock_authenticate.return_value = 'fake_token' + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = {'status': 'deleted'} + mock_delete.return_value = mock_response + + success, answer, _, _ = delete_document('ds1', 'doc1') + self.assertTrue(success) + + @patch('ndi.cloud.api.implementation.documents.list_dataset_documents.authenticate') + @patch('requests.get') + def test_list_dataset_documents(self, mock_get, mock_authenticate): + mock_authenticate.return_value = 'fake_token' + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = [{'id': 'doc1'}] + mock_get.return_value = mock_response + + success, answer, _, _ = list_dataset_documents('ds1') + self.assertTrue(success) + self.assertEqual(len(answer), 1) + +if __name__ == '__main__': + unittest.main()