Refactor the smarts into the api classes.

The object classes are now simple wrappers.
Improve parameter testing, by passing foo="bar" where possible.
This commit is contained in:
sneakypete81 2013-09-10 17:45:53 +01:00
parent 7a7b43afc7
commit 86ba0914c8
18 changed files with 307 additions and 316 deletions

View file

@ -71,7 +71,7 @@ class TestActionCreate(TestActions):
invalid object.
"""
with self.assertRaises(AttributeError):
self.client.action.create(target=object(), foo="bar")
self.client.action.create(target=object())
@mock.patch.object(trovebox.Trovebox, 'post')
def test_action_create_invalid_return_type(self, mock_post):
@ -79,23 +79,23 @@ class TestActionCreate(TestActions):
mock_post.return_value = self._return_value({"target": "test",
"target_type": "invalid"})
with self.assertRaises(NotImplementedError):
self.client.action.create(target=self.test_photos[0], foo="bar")
self.client.action.create(target=self.test_photos[0])
class TestActionDelete(TestActions):
@mock.patch.object(trovebox.Trovebox, 'post')
def test_action_delete(self, mock_post):
"""Check that an action can be deleted"""
mock_post.return_value = self._return_value(True)
result = self.client.action.delete(self.test_actions[0])
mock_post.assert_called_with("/action/1/delete.json")
result = self.client.action.delete(self.test_actions[0], foo="bar")
mock_post.assert_called_with("/action/1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_action_delete_id(self, mock_post):
"""Check that an action can be deleted using its ID"""
mock_post.return_value = self._return_value(True)
result = self.client.action.delete("1")
mock_post.assert_called_with("/action/1/delete.json")
result = self.client.action.delete("1", foo="bar")
mock_post.assert_called_with("/action/1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
@ -110,8 +110,8 @@ class TestActionDelete(TestActions):
"""Check that an action can be deleted using the action object directly"""
mock_post.return_value = self._return_value(True)
action = self.test_actions[0]
result = action.delete()
mock_post.assert_called_with("/action/1/delete.json")
result = action.delete(foo="bar")
mock_post.assert_called_with("/action/1/delete.json", foo="bar")
self.assertEqual(result, True)
self.assertEqual(action.get_fields(), {})
self.assertEqual(action.id, None)

View file

@ -42,8 +42,8 @@ class TestActivitiesList(TestActivities):
"""Check that the activity list is returned correctly"""
mock_get.return_value = self._return_value(self.test_activities_dict)
result = self.client.activities.list()
mock_get.assert_called_with("/activities/list.json")
result = self.client.activities.list(foo="bar")
mock_get.assert_called_with("/activities/list.json", foo="bar")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "1")
self.assertEqual(result[0].type, "photo_upload")
@ -56,16 +56,16 @@ class TestActivitiesList(TestActivities):
def test_empty_result(self, mock_get):
"""Check that an empty result is transformed into an empty list """
mock_get.return_value = self._return_value("")
result = self.client.activities.list()
mock_get.assert_called_with("/activities/list.json")
result = self.client.activities.list(foo="bar")
mock_get.assert_called_with("/activities/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_zero_rows(self, mock_get):
"""Check that totalRows=0 is transformed into an empty list """
mock_get.return_value = self._return_value([{"totalRows": 0}])
result = self.client.activities.list()
mock_get.assert_called_with("/activities/list.json")
result = self.client.activities.list(foo="bar")
mock_get.assert_called_with("/activities/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
@ -73,11 +73,13 @@ class TestActivitiesList(TestActivities):
"""Check that the activity list filters are applied properly"""
mock_get.return_value = self._return_value(self.test_activities_dict)
self.client.activities.list(filters={"foo": "bar",
"test1": "test2"})
"test1": "test2"},
foo="bar")
# Dict element can be any order
self.assertIn(mock_get.call_args[0],
[("/activities/foo-bar/test1-test2/list.json",),
("/activities/test1-test2/foo-bar/list.json",)])
self.assertEqual(mock_get.call_args[1], {"foo": "bar"})
class TestActivitiesPurge(TestActivities):
@mock.patch.object(trovebox.Trovebox, 'post')
@ -135,4 +137,4 @@ class TestActivityView(TestActivities):
mock_get.return_value = self._return_value(self._view_wrapper(
{"data": "", "type": "invalid"}))
with self.assertRaises(NotImplementedError):
self.client.activity.view(self.test_activities[0], foo="bar")
self.client.activity.view(self.test_activities[0])

View file

@ -37,8 +37,8 @@ class TestAlbumsList(TestAlbums):
def test_albums_list(self, mock_get):
"""Check that the album list is returned correctly"""
mock_get.return_value = self._return_value(self.test_albums_dict)
result = self.client.albums.list()
mock_get.assert_called_with("/albums/list.json")
result = self.client.albums.list(foo="bar")
mock_get.assert_called_with("/albums/list.json", foo="bar")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "1")
self.assertEqual(result[0].name, "Album 1")
@ -49,24 +49,24 @@ class TestAlbumsList(TestAlbums):
def test_empty_result(self, mock_get):
"""Check that an empty result is transformed into an empty list """
mock_get.return_value = self._return_value("")
result = self.client.albums.list()
mock_get.assert_called_with("/albums/list.json")
result = self.client.albums.list(foo="bar")
mock_get.assert_called_with("/albums/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_zero_rows(self, mock_get):
"""Check that totalRows=0 is transformed into an empty list """
mock_get.return_value = self._return_value([{"totalRows": 0}])
result = self.client.albums.list()
mock_get.assert_called_with("/albums/list.json")
result = self.client.albums.list(foo="bar")
mock_get.assert_called_with("/albums/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_albums_list_returns_cover_photos(self, mock_get):
"""Check that the album list returns cover photo objects"""
mock_get.return_value = self._return_value(self.test_albums_dict)
result = self.client.albums.list()
mock_get.assert_called_with("/albums/list.json")
result = self.client.albums.list(foo="bar")
mock_get.assert_called_with("/albums/list.json", foo="bar")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "1")
self.assertEqual(result[0].name, "Album 1")
@ -83,7 +83,8 @@ class TestAlbumUpdateCover(TestAlbums):
"""Check that an album cover can be updated"""
mock_post.return_value = self._return_value(self.test_albums_dict[1])
result = self.client.album.cover_update(self.test_albums[0],
self.test_photos[0], foo="bar")
self.test_photos[0],
foo="bar")
mock_post.assert_called_with("/album/1/cover/1a/update.json",
foo="bar")
self.assertEqual(result.id, "2")
@ -134,16 +135,16 @@ class TestAlbumDelete(TestAlbums):
def test_album_delete(self, mock_post):
"""Check that an album can be deleted"""
mock_post.return_value = self._return_value(True)
result = self.client.album.delete(self.test_albums[0])
mock_post.assert_called_with("/album/1/delete.json")
result = self.client.album.delete(self.test_albums[0], foo="bar")
mock_post.assert_called_with("/album/1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_delete_id(self, mock_post):
"""Check that an album can be deleted using its ID"""
mock_post.return_value = self._return_value(True)
result = self.client.album.delete("1")
mock_post.assert_called_with("/album/1/delete.json")
result = self.client.album.delete("1", foo="bar")
mock_post.assert_called_with("/album/1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
@ -158,8 +159,8 @@ class TestAlbumDelete(TestAlbums):
"""Check that an album can be deleted using the album object directly"""
mock_post.return_value = self._return_value(True)
album = self.test_albums[0]
result = album.delete()
mock_post.assert_called_with("/album/1/delete.json")
result = album.delete(foo="bar")
mock_post.assert_called_with("/album/1/delete.json", foo="bar")
self.assertEqual(result, True)
self.assertEqual(album.get_fields(), {})
self.assertEqual(album.id, None)
@ -180,21 +181,23 @@ class TestAlbumAdd(TestAlbums):
def test_album_add(self, mock_post):
""" Check that photos can be added to an album """
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.client.album.add(self.test_albums[0], self.test_photos,
foo="bar")
result = self.client.album.add(self.test_albums[0], self.test_photos,
foo="bar")
mock_post.assert_called_with("/album/1/photo/add.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_add_id(self, mock_post):
""" Check that photos can be added to an album using IDs """
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.client.album.add(self.test_albums[0].id,
objects=["1a", "2b"],
object_type="photo",
foo="bar")
result = self.client.album.add(self.test_albums[0].id,
objects=["1a", "2b"],
object_type="photo",
foo="bar")
mock_post.assert_called_with("/album/1/photo/add.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_object_add(self, mock_post):
@ -203,9 +206,11 @@ class TestAlbumAdd(TestAlbums):
album object directly
"""
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.test_albums[0].add(self.test_photos, foo="bar")
album = self.test_albums[0]
album.add(self.test_photos, foo="bar")
mock_post.assert_called_with("/album/1/photo/add.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(album.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_add_single(self, mock_post):
@ -238,21 +243,23 @@ class TestAlbumRemovePhotos(TestAlbums):
def test_album_remove(self, mock_post):
""" Check that photos can be removed from an album """
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.client.album.remove(self.test_albums[0], self.test_photos,
foo="bar")
result = self.client.album.remove(self.test_albums[0], self.test_photos,
foo="bar")
mock_post.assert_called_with("/album/1/photo/remove.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_remove_id(self, mock_post):
""" Check that photos can be removed from an album using IDs """
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.client.album.remove(self.test_albums[0].id,
objects=["1a", "2b"],
object_type="photo",
foo="bar")
result = self.client.album.remove(self.test_albums[0].id,
objects=["1a", "2b"],
object_type="photo",
foo="bar")
mock_post.assert_called_with("/album/1/photo/remove.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_object_remove(self, mock_post):
@ -261,9 +268,11 @@ class TestAlbumRemovePhotos(TestAlbums):
album object directly
"""
mock_post.return_value = self._return_value(self.test_albums_dict[1])
self.test_albums[0].remove(self.test_photos, foo="bar")
album = self.test_albums[0]
album.remove(self.test_photos, foo="bar")
mock_post.assert_called_with("/album/1/photo/remove.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(album.id, self.test_albums[1].id)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_album_remove_single(self, mock_post):

View file

@ -31,8 +31,8 @@ class TestPhotosList(TestPhotos):
"""Check that the photo list is returned correctly"""
mock_get.return_value = self._return_value(self.test_photos_dict)
result = self.client.photos.list()
mock_get.assert_called_with("/photos/list.json")
result = self.client.photos.list(foo="bar")
mock_get.assert_called_with("/photos/list.json", foo="bar")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "1a")
self.assertEqual(result[0].tags, ["tag1", "tag2"])
@ -43,16 +43,16 @@ class TestPhotosList(TestPhotos):
def test_empty_result(self, mock_get):
"""Check that an empty result is transformed into an empty list """
mock_get.return_value = self._return_value("")
result = self.client.photos.list()
mock_get.assert_called_with("/photos/list.json")
result = self.client.photos.list(foo="bar")
mock_get.assert_called_with("/photos/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_zero_rows(self, mock_get):
"""Check that totalRows=0 is transformed into an empty list """
mock_get.return_value = self._return_value([{"totalRows": 0}])
result = self.client.photos.list()
mock_get.assert_called_with("/photos/list.json")
result = self.client.photos.list(foo="bar")
mock_get.assert_called_with("/photos/list.json", foo="bar")
self.assertEqual(result, [])
class TestPhotosUpdate(TestPhotos):
@ -89,16 +89,18 @@ class TestPhotosDelete(TestPhotos):
def test_photos_delete(self, mock_post):
"""Check that multiple photos can be deleted"""
mock_post.return_value = self._return_value(True)
result = self.client.photos.delete(self.test_photos)
mock_post.assert_called_with("/photos/delete.json", ids=["1a", "2b"])
result = self.client.photos.delete(self.test_photos, foo="bar")
mock_post.assert_called_with("/photos/delete.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_photos_delete_ids(self, mock_post):
"""Check that multiple photos can be deleted using their IDs"""
mock_post.return_value = self._return_value(True)
result = self.client.photos.delete(["1a", "2b"])
mock_post.assert_called_with("/photos/delete.json", ids=["1a", "2b"])
result = self.client.photos.delete(["1a", "2b"], foo="bar")
mock_post.assert_called_with("/photos/delete.json",
ids=["1a", "2b"], foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
@ -116,16 +118,16 @@ class TestPhotoDelete(TestPhotos):
def test_photo_delete(self, mock_post):
"""Check that a photo can be deleted"""
mock_post.return_value = self._return_value(True)
result = self.client.photo.delete(self.test_photos[0])
mock_post.assert_called_with("/photo/1a/delete.json")
result = self.client.photo.delete(self.test_photos[0], foo="bar")
mock_post.assert_called_with("/photo/1a/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_photo_delete_id(self, mock_post):
"""Check that a photo can be deleted using its ID"""
mock_post.return_value = self._return_value(True)
result = self.client.photo.delete("1a")
mock_post.assert_called_with("/photo/1a/delete.json")
result = self.client.photo.delete("1a", foo="bar")
mock_post.assert_called_with("/photo/1a/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
@ -143,8 +145,8 @@ class TestPhotoDelete(TestPhotos):
"""
mock_post.return_value = self._return_value(True)
photo = self.test_photos[0]
result = photo.delete()
mock_post.assert_called_with("/photo/1a/delete.json")
result = photo.delete(foo="bar")
mock_post.assert_called_with("/photo/1a/delete.json", foo="bar")
self.assertEqual(result, True)
self.assertEqual(photo.get_fields(), {})
self.assertEqual(photo.id, None)
@ -309,8 +311,10 @@ class TestPhotoNextPrevious(TestPhotos):
mock_get.return_value = self._return_value(
{"next": [self.test_photos_dict[0]],
"previous": [self.test_photos_dict[1]]})
result = self.client.photo.next_previous(self.test_photos[0])
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.client.photo.next_previous(self.test_photos[0],
foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["next"][0].get_fields(),
self.test_photos_dict[0])
self.assertEqual(result["previous"][0].get_fields(),
@ -325,8 +329,9 @@ class TestPhotoNextPrevious(TestPhotos):
mock_get.return_value = self._return_value(
{"next": [self.test_photos_dict[0]],
"previous": [self.test_photos_dict[1]]})
result = self.client.photo.next_previous("1a")
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.client.photo.next_previous("1a", foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["next"][0].get_fields(),
self.test_photos_dict[0])
self.assertEqual(result["previous"][0].get_fields(),
@ -341,8 +346,9 @@ class TestPhotoNextPrevious(TestPhotos):
mock_get.return_value = self._return_value(
{"next": [self.test_photos_dict[0]],
"previous": [self.test_photos_dict[1]]})
result = self.test_photos[0].next_previous()
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.test_photos[0].next_previous(foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["next"][0].get_fields(),
self.test_photos_dict[0])
self.assertEqual(result["previous"][0].get_fields(),
@ -353,8 +359,10 @@ class TestPhotoNextPrevious(TestPhotos):
"""Check that the next photos are returned"""
mock_get.return_value = self._return_value(
{"next": [self.test_photos_dict[0]]})
result = self.client.photo.next_previous(self.test_photos[0])
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.client.photo.next_previous(self.test_photos[0],
foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["next"][0].get_fields(),
self.test_photos_dict[0])
self.assertNotIn("previous", result)
@ -364,8 +372,10 @@ class TestPhotoNextPrevious(TestPhotos):
"""Check that the previous photos are returned"""
mock_get.return_value = self._return_value(
{"previous": [self.test_photos_dict[1]]})
result = self.client.photo.next_previous(self.test_photos[0])
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.client.photo.next_previous(self.test_photos[0],
foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["previous"][0].get_fields(),
self.test_photos_dict[1])
self.assertNotIn("next", result)
@ -376,8 +386,10 @@ class TestPhotoNextPrevious(TestPhotos):
mock_get.return_value = self._return_value(
{"next": [self.test_photos_dict[0], self.test_photos_dict[0]],
"previous": [self.test_photos_dict[1], self.test_photos_dict[1]]})
result = self.client.photo.next_previous(self.test_photos[0])
mock_get.assert_called_with("/photo/1a/nextprevious.json")
result = self.client.photo.next_previous(self.test_photos[0],
foo="bar")
mock_get.assert_called_with("/photo/1a/nextprevious.json",
foo="bar")
self.assertEqual(result["next"][0].get_fields(),
self.test_photos_dict[0])
self.assertEqual(result["next"][1].get_fields(),

View file

@ -27,8 +27,8 @@ class TestTagsList(TestTags):
def test_tags_list(self, mock_get):
"""Check that the tag list is returned correctly"""
mock_get.return_value = self._return_value(self.test_tags_dict)
result = self.client.tags.list()
mock_get.assert_called_with("/tags/list.json")
result = self.client.tags.list(foo="bar")
mock_get.assert_called_with("/tags/list.json", foo="bar")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "tag1")
self.assertEqual(result[0].count, 11)
@ -39,16 +39,16 @@ class TestTagsList(TestTags):
def test_empty_result(self, mock_get):
"""Check that an empty result is transformed into an empty list """
mock_get.return_value = self._return_value("")
result = self.client.tags.list()
mock_get.assert_called_with("/tags/list.json")
result = self.client.tags.list(foo="bar")
mock_get.assert_called_with("/tags/list.json", foo="bar")
self.assertEqual(result, [])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_zero_rows(self, mock_get):
"""Check that totalRows=0 is transformed into an empty list """
mock_get.return_value = self._return_value([{"totalRows": 0}])
result = self.client.tags.list()
mock_get.assert_called_with("/tags/list.json")
result = self.client.tags.list(foo="bar")
mock_get.assert_called_with("/tags/list.json", foo="bar")
self.assertEqual(result, [])
class TestTagCreate(TestTags):
@ -56,8 +56,9 @@ class TestTagCreate(TestTags):
def test_tag_create(self, mock_post):
"""Check that a tag can be created"""
mock_post.return_value = self._return_value(True)
result = self.client.tag.create("test")
mock_post.assert_called_with("/tag/create.json", tag="test")
result = self.client.tag.create("test", foo="bar")
mock_post.assert_called_with("/tag/create.json", tag="test",
foo="bar")
self.assertEqual(result, True)
class TestTagDelete(TestTags):
@ -65,16 +66,16 @@ class TestTagDelete(TestTags):
def test_tag_delete(self, mock_post):
"""Check that a tag can be deleted"""
mock_post.return_value = self._return_value(True)
result = self.client.tag.delete(self.test_tags[0])
mock_post.assert_called_with("/tag/tag1/delete.json")
result = self.client.tag.delete(self.test_tags[0], foo="bar")
mock_post.assert_called_with("/tag/tag1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_tag_delete_id(self, mock_post):
"""Check that a tag can be deleted using its ID"""
mock_post.return_value = self._return_value(True)
result = self.client.tag.delete("tag1")
mock_post.assert_called_with("/tag/tag1/delete.json")
result = self.client.tag.delete("tag1", foo="bar")
mock_post.assert_called_with("/tag/tag1/delete.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
@ -89,8 +90,8 @@ class TestTagDelete(TestTags):
"""Check that a tag can be deleted when using the tag object directly"""
mock_post.return_value = self._return_value(True)
tag = self.test_tags[0]
result = tag.delete()
mock_post.assert_called_with("/tag/tag1/delete.json")
result = tag.delete(foo="bar")
mock_post.assert_called_with("/tag/tag1/delete.json", foo="bar")
self.assertEqual(result, True)
self.assertEqual(tag.get_fields(), {})
self.assertEqual(tag.id, None)

View file

@ -14,7 +14,7 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_al
--- original/api/api_album.py
+++ patched/api/api_album.py
@@ -8,7 +8,7 @@
from trovebox import http
from trovebox.objects.album import Album
from .api_base import ApiBase
-class ApiAlbums(ApiBase):
@ -37,7 +37,16 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_ba
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_tag.py patched/api/api_tag.py
--- original/api/api_tag.py
+++ patched/api/api_tag.py
@@ -5,7 +5,7 @@
@@ -2,7 +2,7 @@
api_tag.py : Trovebox Tag API Classes
"""
try:
- from urllib.parse import quote # Python3
+ from urllib.parse import quote # Python3 # pylint: disable=import-error,no-name-in-module
except ImportError:
from urllib import quote # Python2
@@ -10,7 +10,7 @@
from trovebox.objects.tag import Tag
from .api_base import ApiBase
@ -159,27 +168,15 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/main.py pa
files=files, **params)
for file_ in files:
files[file_].close()
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/tag.py patched/objects/tag.py
--- original/objects/tag.py
+++ patched/objects/tag.py
@@ -2,7 +2,7 @@
Representation of a Tag object
"""
try:
- from urllib.parse import quote # Python3
+ from urllib.parse import quote # Python3 # pylint: disable=import-error,no-name-in-module
except ImportError:
from urllib import quote # Python2
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/trovebox_object.py patched/objects/trovebox_object.py
--- original/objects/trovebox_object.py
+++ patched/objects/trovebox_object.py
@@ -5,7 +5,7 @@
""" Base object supporting the storage of custom fields as attributes """
def __init__(self, trovebox, json_dict):
self._type = "None"
_type = "None"
def __init__(self, client, json_dict):
- self.id = None
+ self.id = None # pylint: disable=invalid-name
self.name = None
self._trovebox = trovebox
self._client = client
self._json_dict = json_dict

View file

@ -1,6 +1,7 @@
"""
api_action.py : Trovebox Action API Classes
"""
from trovebox.errors import TroveboxError
from trovebox.objects.action import Action
from .api_base import ApiBase
@ -15,15 +16,14 @@ class ApiAction(ApiBase):
If a Trovebox object is used, the target type is inferred
automatically.
"""
# Extract the type from the target
# Extract the target type
if target_type is None:
target_type = target.get_type()
# Extract the ID from the target
# Extract the target ID
try:
target_id = target.id
except AttributeError:
# Assume the ID was passed in directly
target_id = target
result = self._client.post("/action/%s/%s/create.json" %
@ -39,9 +39,12 @@ class ApiAction(ApiBase):
Returns True if successful.
Raises a TroveboxError if not.
"""
if not isinstance(action, Action):
action = Action(self._client, {"id": action})
return action.delete(**kwds)
result = self._client.post("/action/%s/delete.json" %
self._extract_id(action),
**kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
return result
def view(self, action, **kwds):
"""
@ -50,7 +53,7 @@ class ApiAction(ApiBase):
Requests all properties of an action.
Returns the requested action object.
"""
if not isinstance(action, Action):
action = Action(self._client, {"id": action})
action.view(**kwds)
return action
result = self._client.get("/action/%s/view.json" %
self._extract_id(action),
**kwds)["result"]
return Action(self._client, result)

View file

@ -1,7 +1,7 @@
"""
api_activity.py : Trovebox Activity API Classes
"""
from trovebox import http
import json
from trovebox.errors import TroveboxError
from trovebox.objects.activity import Activity
from .api_base import ApiBase
@ -19,7 +19,7 @@ class ApiActivities(ApiBase):
filter_string = self._build_filter_string(filters)
activities = self._client.get("/activities/%slist.json" % filter_string,
**kwds)["result"]
activities = http.result_to_list(activities)
activities = self._result_to_list(activities)
return [Activity(self._client, activity) for activity in activities]
def purge(self, **kwds):
@ -42,7 +42,11 @@ class ApiActivity(ApiBase):
Requests all properties of an activity.
Returns the requested activity object.
"""
if not isinstance(activity, Activity):
activity = Activity(self._client, {"id": activity})
activity.view(**kwds)
return activity
result = self._client.get("/activity/%s/view.json" %
self._extract_id(activity),
**kwds)["result"]
# TBD: Why is the result enclosed/encoded like this?
result = result["0"]
result["data"] = json.loads(result["data"])
return Activity(self._client, result)

View file

@ -3,9 +3,9 @@ api_album.py : Trovebox Album API Classes
"""
import collections
from trovebox.errors import TroveboxError
from trovebox.objects.trovebox_object import TroveboxObject
from trovebox.objects.album import Album
from trovebox import http
from .api_base import ApiBase
class ApiAlbums(ApiBase):
@ -17,7 +17,7 @@ class ApiAlbums(ApiBase):
Returns a list of Album objects.
"""
albums = self._client.get("/albums/list.json", **kwds)["result"]
albums = http.result_to_list(albums)
albums = self._result_to_list(albums)
return [Album(self._client, album) for album in albums]
class ApiAlbum(ApiBase):
@ -29,10 +29,18 @@ class ApiAlbum(ApiBase):
Update the cover photo of an album.
Returns the updated album object.
"""
if not isinstance(album, Album):
album = Album(self._client, {"id": album})
album.cover_update(photo, **kwds)
return album
result = self._client.post("/album/%s/cover/%s/update.json" %
(self._extract_id(album),
self._extract_id(photo)),
**kwds)["result"]
# API currently doesn't return the updated album
# (frontend issue #1369)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self._extract_id(album))["result"]
return Album(self._client, result)
def create(self, name, **kwds):
"""
@ -52,9 +60,12 @@ class ApiAlbum(ApiBase):
Returns True if successful.
Raises a TroveboxError if not.
"""
if not isinstance(album, Album):
album = Album(self._client, {"id": album})
return album.delete(**kwds)
result = self._client.post("/album/%s/delete.json" %
self._extract_id(album),
**kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
return result
def add(self, album, objects, object_type=None, **kwds):
"""
@ -64,7 +75,7 @@ class ApiAlbum(ApiBase):
The objects are a list of either IDs or Trovebox objects.
If Trovebox objects are used, the object type is inferred
automatically.
Returns True if the album was updated successfully.
Returns the updated album object.
"""
return self._add_remove("add", album, objects, object_type,
**kwds)
@ -77,7 +88,7 @@ class ApiAlbum(ApiBase):
The objects are a list of either IDs or Trovebox objects.
If Trovebox objects are used, the object type is inferred
automatically.
Returns True if the album was updated successfully.
Returns the updated album object.
"""
return self._add_remove("remove", album, objects, object_type,
**kwds)
@ -85,10 +96,6 @@ class ApiAlbum(ApiBase):
def _add_remove(self, action, album, objects, object_type=None,
**kwds):
"""Common code for the add and remove endpoints."""
# Extract the id of the album
if isinstance(album, Album):
album = album.id
# Ensure we have an iterable of objects
if not isinstance(objects, collections.Iterable):
objects = [objects]
@ -106,9 +113,17 @@ class ApiAlbum(ApiBase):
# Extract the ids of the objects
objects[i] = obj.id
return self._client.post("/album/%s/%s/%s.json" %
(album, object_type, action),
ids=objects, **kwds)["result"]
result = self._client.post("/album/%s/%s/%s.json" %
(self._extract_id(album),
object_type, action),
ids=objects, **kwds)["result"]
# API currently doesn't return the updated album
# (frontend issue #1369)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self._extract_id(album))["result"]
return Album(self._client, result)
def update(self, album, **kwds):
"""
@ -117,10 +132,16 @@ class ApiAlbum(ApiBase):
Updates an album with the specified parameters.
Returns the updated album object.
"""
if not isinstance(album, Album):
album = Album(self._client, {"id": album})
album.update(**kwds)
return album
result = self._client.post("/album/%s/update.json" %
self._extract_id(album),
**kwds)["result"]
# APIv1 doesn't return the updated album (frontend issue #937)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self._extract_id(album))["result"]
return Album(self._client, result)
def view(self, album, **kwds):
"""
@ -129,7 +150,7 @@ class ApiAlbum(ApiBase):
Requests all properties of an album.
Returns the requested album object.
"""
if not isinstance(album, Album):
album = Album(self._client, {"id": album})
album.view(**kwds)
return album
result = self._client.get("/album/%s/view.json" %
self._extract_id(album),
**kwds)["result"]
return Album(self._client, result)

View file

@ -18,3 +18,21 @@ class ApiBase(object):
for filt in filters:
filter_string += "%s-%s/" % (filt, filters[filt])
return filter_string
@staticmethod
def _extract_id(obj):
""" Return obj.id, or obj if the object doesn't have an ID """
try:
return obj.id
except AttributeError:
return obj
@staticmethod
def _result_to_list(result):
""" Handle the case where the result contains no items """
if not result:
return []
if "totalRows" in result[0] and result[0]["totalRows"] == 0:
return []
else:
return result

View file

@ -3,24 +3,10 @@ api_photo.py : Trovebox Photo API Classes
"""
import base64
from trovebox import http
from trovebox.errors import TroveboxError
from trovebox.objects.photo import Photo
from .api_base import ApiBase
def _extract_ids(photos):
"""
Given a list of objects, extract the photo id for each Photo
object.
"""
ids = []
for photo in photos:
if isinstance(photo, Photo):
ids.append(photo.id)
else:
ids.append(photo)
return ids
class ApiPhotos(ApiBase):
""" Definitions of /photos/ API endpoints """
# TODO: Add options
@ -31,7 +17,7 @@ class ApiPhotos(ApiBase):
Returns a list of Photo objects.
"""
photos = self._client.get("/photos/list.json", **kwds)["result"]
photos = http.result_to_list(photos)
photos = self._result_to_list(photos)
return [Photo(self._client, photo) for photo in photos]
# def share(self, **kwds):
@ -44,7 +30,7 @@ class ApiPhotos(ApiBase):
Returns True if successful.
Raises a TroveboxError if not.
"""
ids = _extract_ids(photos)
ids = [self._extract_id(photo) for photo in photos]
if not self._client.post("/photos/delete.json", ids=ids,
**kwds)["result"]:
raise TroveboxError("Delete response returned False")
@ -58,7 +44,7 @@ class ApiPhotos(ApiBase):
Returns True if successful.
Raises TroveboxError if not.
"""
ids = _extract_ids(photos)
ids = [self._extract_id(photo) for photo in photos]
if not self._client.post("/photos/update.json", ids=ids,
**kwds)["result"]:
raise TroveboxError("Update response returned False")
@ -74,9 +60,12 @@ class ApiPhoto(ApiBase):
Returns True if successful.
Raises a TroveboxError if not.
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
return photo.delete(**kwds)
result = self._client.post("/photo/%s/delete.json" %
self._extract_id(photo),
**kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
return result
# def delete_source(self, photo, **kwds):
@ -95,10 +84,10 @@ class ApiPhoto(ApiBase):
Updates a photo with the specified parameters.
Returns the updated photo object.
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
photo.update(**kwds)
return photo
result = self._client.post("/photo/%s/update.json" %
self._extract_id(photo),
**kwds)["result"]
return Photo(self._client, result)
# TODO: Add options
def view(self, photo, **kwds):
@ -110,10 +99,10 @@ class ApiPhoto(ApiBase):
by using the "returnSizes" parameter.
Returns the requested photo object.
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
photo.view(**kwds)
return photo
result = self._client.get("/photo/%s/view.json" %
self._extract_id(photo),
**kwds)["result"]
return Photo(self._client, result)
def upload(self, photo_file, **kwds):
"""
@ -151,9 +140,29 @@ class ApiPhoto(ApiBase):
Returns a dict containing the next and previous photo lists
(there may be more than one next/previous photo returned).
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
return photo.next_previous(**kwds)
result = self._client.get("/photo/%s/nextprevious.json" %
self._extract_id(photo),
**kwds)["result"]
value = {}
if "next" in result:
# Workaround for APIv1
if not isinstance(result["next"], list): # pragma: no cover
result["next"] = [result["next"]]
value["next"] = []
for photo in result["next"]:
value["next"].append(Photo(self._client, photo))
if "previous" in result:
# Workaround for APIv1
if not isinstance(result["previous"], list): # pragma: no cover
result["previous"] = [result["previous"]]
value["previous"] = []
for photo in result["previous"]:
value["previous"].append(Photo(self._client, photo))
return value
def transform(self, photo, **kwds):
"""
@ -163,7 +172,13 @@ class ApiPhoto(ApiBase):
eg. transform(photo, rotate=90)
Returns the transformed photo.
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
photo.transform(**kwds)
return photo
result = self._client.post("/photo/%s/transform.json" %
self._extract_id(photo),
**kwds)["result"]
# APIv1 doesn't return the transformed photo (frontend issue #955)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/photo/%s/view.json" %
self._extract_id(photo))["result"]
return Photo(self._client, result)

View file

@ -1,7 +1,12 @@
"""
api_tag.py : Trovebox Tag API Classes
"""
from trovebox import http
try:
from urllib.parse import quote # Python3
except ImportError:
from urllib import quote # Python2
from trovebox.errors import TroveboxError
from trovebox.objects.tag import Tag
from .api_base import ApiBase
@ -14,7 +19,7 @@ class ApiTags(ApiBase):
Returns a list of Tag objects.
"""
tags = self._client.get("/tags/list.json", **kwds)["result"]
tags = http.result_to_list(tags)
tags = self._result_to_list(tags)
return [Tag(self._client, tag) for tag in tags]
class ApiTag(ApiBase):
@ -37,9 +42,12 @@ class ApiTag(ApiBase):
Returns True if successful.
Raises a TroveboxError if not.
"""
if not isinstance(tag, Tag):
tag = Tag(self._client, {"id": tag})
return tag.delete(**kwds)
result = self._client.post("/tag/%s/delete.json" %
quote(self._extract_id(tag)),
**kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
return result
def update(self, tag, **kwds):
"""
@ -48,9 +56,9 @@ class ApiTag(ApiBase):
Updates a tag with the specified parameters.
Returns the updated tag object.
"""
if not isinstance(tag, Tag):
tag = Tag(self._client, {"id": tag})
tag.update(**kwds)
return tag
result = self._client.post("/tag/%s/update.json" %
quote(self._extract_id(tag)),
**kwds)["result"]
return Tag(self._client, result)
# def view(self, tag, **kwds):

View file

@ -249,12 +249,3 @@ class Http(object):
raise TroveboxDuplicateError("Code %d: %s" % (code, message))
else:
raise TroveboxError("Code %d: %s" % (code, message))
def result_to_list(result):
""" Handle the case where the result contains no items """
if not result:
return []
if "totalRows" in result[0] and result[0]["totalRows"] == 0:
return []
else:
return result

View file

@ -1,7 +1,6 @@
"""
Representation of an Action object
"""
from trovebox.errors import TroveboxError
from .trovebox_object import TroveboxObject
from .photo import Photo
@ -33,10 +32,7 @@ class Action(TroveboxObject):
Returns True if successful.
Raises a TroveboxError if not.
"""
result = self._client.post("/action/%s/delete.json" %
self.id, **kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
result = self._client.action.delete(self, **kwds)
self._delete_fields()
return result
@ -45,9 +41,8 @@ class Action(TroveboxObject):
Endpoint: /action/<id>/view.json
Requests the full contents of the action.
Updates the action's fields with the response.
Updates the action object's fields with the response.
"""
result = self._client.get("/action/%s/view.json" %
self.id, **kwds)["result"]
self._replace_fields(result)
result = self._client.action.view(self, **kwds)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()

View file

@ -1,8 +1,6 @@
"""
Representation of an Activity object
"""
import json
from .trovebox_object import TroveboxObject
from .photo import Photo
@ -33,12 +31,7 @@ class Activity(TroveboxObject):
Requests the full contents of the activity.
Updates the activity's fields with the response.
"""
result = self._client.get("/activity/%s/view.json" %
self.id, **kwds)["result"]
# TBD: Why is the result enclosed/encoded like this?
result = result["0"]
result["data"] = json.loads(result["data"])
self._replace_fields(result)
result = self._client.activity.view(self, **kwds)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()

View file

@ -1,7 +1,6 @@
"""
Representation of an Album object
"""
from trovebox.errors import TroveboxError
from .trovebox_object import TroveboxObject
from .photo import Photo
@ -38,19 +37,8 @@ class Album(TroveboxObject):
Update the cover photo of this album.
"""
if not isinstance(photo, Photo):
photo = Photo(self._client, {"id": photo})
result = self._client.post("/album/%s/cover/%s/update.json" %
(self.id, photo.id),
**kwds)["result"]
# API currently doesn't return the updated album
# (frontend issue #1369)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self.id)["result"]
self._replace_fields(result)
result = self._client.album.cover_update(self, photo, **kwds)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()
def delete(self, **kwds):
@ -61,10 +49,7 @@ class Album(TroveboxObject):
Returns True if successful.
Raises a TroveboxError if not.
"""
result = self._client.post("/album/%s/delete.json" %
self.id, **kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
result = self._client.album.delete(self, **kwds)
self._delete_fields()
return result
@ -79,13 +64,7 @@ class Album(TroveboxObject):
Updates the album's fields with the response.
"""
result = self._client.album.add(self, objects, object_type, **kwds)
# API currently doesn't return the updated album
# (frontend issue #1369)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self.id)["result"]
self._replace_fields(result)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()
def remove(self, objects, object_type=None, **kwds):
@ -100,12 +79,7 @@ class Album(TroveboxObject):
"""
result = self._client.album.remove(self, objects, object_type,
**kwds)
# API currently doesn't return the updated album
# (frontend issue #1369)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self.id)["result"]
self._replace_fields(result)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()
def update(self, **kwds):
@ -114,15 +88,8 @@ class Album(TroveboxObject):
Updates this album with the specified parameters.
"""
result = self._client.post("/album/%s/update.json" %
self.id, **kwds)["result"]
# APIv1 doesn't return the updated album (frontend issue #937)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/album/%s/view.json" %
self.id)["result"]
self._replace_fields(result)
result = self._client.album.update(self, **kwds)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()
def view(self, **kwds):
@ -132,7 +99,6 @@ class Album(TroveboxObject):
Requests all properties of an album.
Updates the album's fields with the response.
"""
result = self._client.get("/album/%s/view.json" %
self.id, **kwds)["result"]
self._replace_fields(result)
result = self._client.album.view(self, **kwds)
self._replace_fields(result.get_fields())
self._update_fields_with_objects()

View file

@ -1,7 +1,6 @@
"""
Representation of a Photo object
"""
from trovebox.errors import TroveboxError
from .trovebox_object import TroveboxObject
class Photo(TroveboxObject):
@ -16,10 +15,7 @@ class Photo(TroveboxObject):
Returns True if successful.
Raises a TroveboxError if not.
"""
result = self._client.post("/photo/%s/delete.json" %
self.id, **kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
result = self._client.photo.delete(self, **kwds)
self._delete_fields()
return result
@ -39,9 +35,8 @@ class Photo(TroveboxObject):
Updates this photo with the specified parameters.
"""
result = self._client.post("/photo/%s/update.json" %
self.id, **kwds)["result"]
self._replace_fields(result)
result = self._client.photo.update(self, **kwds)
self._replace_fields(result.get_fields())
# TODO: Add options
def view(self, **kwds):
@ -53,9 +48,8 @@ class Photo(TroveboxObject):
by using the "returnSizes" parameter.
Updates the photo's fields with the response.
"""
result = self._client.get("/photo/%s/view.json" %
self.id, **kwds)["result"]
self._replace_fields(result)
result = self._client.photo.view(self, **kwds)
self._replace_fields(result.get_fields())
def dynamic_url(self, **kwds):
""" Not implemented yet """
@ -69,28 +63,7 @@ class Photo(TroveboxObject):
Returns a dict containing the next and previous photo lists
(there may be more than one next/previous photo returned).
"""
result = self._client.get("/photo/%s/nextprevious.json" %
self.id, **kwds)["result"]
value = {}
if "next" in result:
# Workaround for APIv1
if not isinstance(result["next"], list): # pragma: no cover
result["next"] = [result["next"]]
value["next"] = []
for photo in result["next"]:
value["next"].append(Photo(self._client, photo))
if "previous" in result:
# Workaround for APIv1
if not isinstance(result["previous"], list): # pragma: no cover
result["previous"] = [result["previous"]]
value["previous"] = []
for photo in result["previous"]:
value["previous"].append(Photo(self._client, photo))
return value
return self._client.photo.next_previous(self, **kwds)
def transform(self, **kwds):
"""
@ -100,12 +73,5 @@ class Photo(TroveboxObject):
eg. transform(photo, rotate=90)
Updates the photo's fields with the response.
"""
result = self._client.post("/photo/%s/transform.json" %
self.id, **kwds)["result"]
# APIv1 doesn't return the transformed photo (frontend issue #955)
if isinstance(result, bool): # pragma: no cover
result = self._client.get("/photo/%s/view.json" %
self.id)["result"]
self._replace_fields(result)
result = self._client.photo.transform(self, **kwds)
self._replace_fields(result.get_fields())

View file

@ -1,12 +1,6 @@
"""
Representation of a Tag object
"""
try:
from urllib.parse import quote # Python3
except ImportError:
from urllib import quote # Python2
from trovebox.errors import TroveboxError
from .trovebox_object import TroveboxObject
class Tag(TroveboxObject):
@ -21,10 +15,7 @@ class Tag(TroveboxObject):
Returns True if successful.
Raises a TroveboxError if not.
"""
result = self._client.post("/tag/%s/delete.json" %
quote(self.id), **kwds)["result"]
if not result:
raise TroveboxError("Delete response returned False")
result = self._client.tag.delete(self, **kwds)
self._delete_fields()
return result
@ -35,8 +26,7 @@ class Tag(TroveboxObject):
Updates this tag with the specified parameters.
Returns the updated tag object.
"""
result = self._client.post("/tag/%s/update.json" % quote(self.id),
**kwds)["result"]
self._replace_fields(result)
result = self._client.tag.update(self, **kwds)
self._replace_fields(result.get_fields())
# def view(self, **kwds):