From 93258c8bbf81745b230e5d5627e318ccf0cb634a Mon Sep 17 00:00:00 2001 From: Flavio Amieiro Date: Mon, 6 Jun 2016 23:02:00 -0300 Subject: [PATCH 1/3] Adds method to delete corpus This method allows a user to delete the corpus using the corpus object itself, instead of needing to use `requests.delete` and the corpus url. --- pypln/api.py | 16 ++++++++++++++++ tests/test_pypln.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/pypln/api.py b/pypln/api.py index 6eb4068..3a3aa23 100644 --- a/pypln/api.py +++ b/pypln/api.py @@ -209,6 +209,22 @@ def add_documents(self, documents): return result, errors + def delete(self): + ''' + Deletes the corpus. Be very careful, since this operation is + irreversible. + + Returns True if the Corpus was successfully deleted, raises + RuntimeError otherwise. + ''' + result = self.session.delete(self.url) + if result.status_code == 204: + return True + else: + raise RuntimeError("Corpus deletion failed with status " + "{}. The response was: '{}'".format(result.status_code, + result.text)) + class PyPLN(object): """ Class to connect to PyPLN's API and execute some actions diff --git a/tests/test_pypln.py b/tests/test_pypln.py index 5d6efa3..937f210 100644 --- a/tests/test_pypln.py +++ b/tests/test_pypln.py @@ -379,6 +379,27 @@ def test_adding_multiple_documents_returns_an_error(self, mocked_add_document): self.assertEqual(result[1][0][0], expected[1][0][0]) self.assertIsInstance(expected[1][0][1], RuntimeError) + @patch("requests.Session.delete") + def test_delete_corpus(self, mocked_delete): + mocked_delete.return_value.status_code = 204 + + corpus = Corpus(session=self.session, **self.example_json) + result = corpus.delete() + + mocked_delete.assert_called_with(self.example_json['url']) + self.assertTrue(result) + + @patch("requests.Session.delete") + def test_corpus_deletion_fails(self, mocked_delete): + mocked_delete.return_value.status_code = 403 + + session = requests.Session() + session.auth = ('wrong_user', 'my_precious') + corpus = Corpus(session=session, **self.example_json) + + with self.assertRaises(RuntimeError): + corpus.delete() + class DocumentTest(unittest.TestCase): From fe7e993812a603c98e3967caccb1e0de8eef83f1 Mon Sep 17 00:00:00 2001 From: Flavio Amieiro Date: Mon, 6 Jun 2016 23:11:38 -0300 Subject: [PATCH 2/3] Adds method to delete document This method allows a user to delete a document using the document object itself, instead of needing to use `requests.delete` and the document url. --- pypln/api.py | 16 ++++++++++++++++ tests/test_pypln.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/pypln/api.py b/pypln/api.py index 3a3aa23..e2dabd5 100644 --- a/pypln/api.py +++ b/pypln/api.py @@ -128,6 +128,22 @@ def properties(self): "{}. The response was: '{}'".format(response.status_code, response.text)) + def delete(self): + ''' + Deletes the document. Be very careful, since this operation is + irreversible. + + Returns True if the Document was successfully deleted, raises + RuntimeError otherwise. + ''' + result = self.session.delete(self.url) + if result.status_code == 204: + return True + else: + raise RuntimeError("Document deletion failed with status " + "{}. The response was: '{}'".format(result.status_code, + result.text)) + class Corpus(object): '''Class that represents a Corpus in PyPLN''' diff --git a/tests/test_pypln.py b/tests/test_pypln.py index 937f210..6fe205d 100644 --- a/tests/test_pypln.py +++ b/tests/test_pypln.py @@ -603,3 +603,24 @@ def test_download_wordcloud(self, mocked_get): handle.write.assert_called_once_with(png.decode('ascii')) mocked_get.assert_called_with(self.example_json['properties'] + 'wordcloud') + + @patch("requests.Session.delete") + def test_delete_document(self, mocked_delete): + mocked_delete.return_value.status_code = 204 + + document = Document(session=self.session, **self.example_json) + result = document.delete() + + mocked_delete.assert_called_with(self.example_json['url']) + self.assertTrue(result) + + @patch("requests.Session.delete") + def test_document_deletion_fails(self, mocked_delete): + mocked_delete.return_value.status_code = 403 + + session = requests.Session() + session.auth = ('wrong_user', 'my_precious') + document = Document(session=session, **self.example_json) + + with self.assertRaises(RuntimeError): + document.delete() From f39c5278d258a00d629eadff068327c8f534cd8c Mon Sep 17 00:00:00 2001 From: Flavio Amieiro Date: Tue, 7 Jun 2016 00:25:51 -0300 Subject: [PATCH 3/3] Returns `Document` instances in `corpus.documents` This *breaks backwards compatibility*. This means we probably need to bump the major version before we merge this into master and publish to pypi. --- pypln/api.py | 3 +++ tests/test_pypln.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pypln/api.py b/pypln/api.py index e2dabd5..76961b0 100644 --- a/pypln/api.py +++ b/pypln/api.py @@ -156,6 +156,9 @@ def __init__(self, session, *args, **kwargs): ''' self.session = session for key, value in kwargs.items(): + if key == 'documents': + value = map(lambda d: Document(session=self.session, **d), + value) setattr(self, key, value) splited_url = urlsplit(self.url) diff --git a/tests/test_pypln.py b/tests/test_pypln.py index 6fe205d..d9987f3 100644 --- a/tests/test_pypln.py +++ b/tests/test_pypln.py @@ -400,6 +400,51 @@ def test_corpus_deletion_fails(self, mocked_delete): with self.assertRaises(RuntimeError): corpus.delete() + def test_get_all_documents(self): + example_document_2 = { + 'owner': 'user', + 'corpus': 'http://pypln.example.com/corpora/42/', + 'size': 43, + 'properties': 'http://pypln.example.com/documents/124/properties', + 'url': 'http://pypln.example.com/documents/124/', + 'blob': '/test_2.txt', + 'uploaded_at': '2013-10-25T17:00:01.000Z', + } + + expected_documents = [ + Document(session=self.session, **self.example_document), + Document(session=self.session, **example_document_2) + ] + + self.example_json['documents'] = [self.example_document, + example_document_2] + + corpus = Corpus(session=self.session, **self.example_json) + + for document in corpus.documents: + self.assertIsInstance(document, Document) + + retrieved_document_1 = corpus.documents[0] + retrieved_document_2 = corpus.documents[1] + + for key, value in self.example_document.items(): + # `properties` is a method on `Document` class, so replacing with + # `properties_url` to test each key/value + if key == 'properties': + key = 'properties_url' + self.assertEqual(value, getattr(retrieved_document_1, key)) + + for key, value in example_document_2.items(): + # `properties` is a method on `Document` class, so replacing with + # `properties_url` to test each key/value + if key == 'properties': + key = 'properties_url' + self.assertEqual(value, getattr(retrieved_document_2, key)) + + # Document objects should link `session` object from the Corpus + self.assertIs(retrieved_document_1.session, corpus.session) + self.assertIs(retrieved_document_2.session, corpus.session) + class DocumentTest(unittest.TestCase):