Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: feature/api improvements #41

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pypln/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'''
Expand All @@ -140,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),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this, because its way more usefull for API users. No need to worry about breaking compatibility since we don't have many users yet. But we should make a clear note about this in some form of release note.

value)
setattr(self, key, value)

splited_url = urlsplit(self.url)
Expand Down Expand Up @@ -209,6 +228,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
Expand Down
87 changes: 87 additions & 0 deletions tests/test_pypln.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,72 @@ 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()

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):

Expand Down Expand Up @@ -582,3 +648,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()