Add cacheable parameter for 16 functions that call _collect_nodes(). There's some 112 that call _request() and some may be made cacheable, but they can be done if someone asks for it. Closes #88.
This commit is contained in:
parent
1fc02a33c5
commit
1d1eba5af7
62
pylast.py
62
pylast.py
|
@ -1676,13 +1676,13 @@ class Artist(_BaseObject, _Taggable):
|
||||||
)
|
)
|
||||||
return images
|
return images
|
||||||
|
|
||||||
def get_shouts(self, limit=50):
|
def get_shouts(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequqence of Shout objects
|
Returns a sequqence of Shout objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shouts = []
|
shouts = []
|
||||||
for node in _collect_nodes(limit, self, "artist.getShouts", False):
|
for node in _collect_nodes(limit, self, "artist.getShouts", cacheable):
|
||||||
shouts.append(Shout(
|
shouts.append(Shout(
|
||||||
_extract(node, "body"),
|
_extract(node, "body"),
|
||||||
User(_extract(node, "author"), self.network),
|
User(_extract(node, "author"), self.network),
|
||||||
|
@ -1886,13 +1886,13 @@ class Event(_BaseObject):
|
||||||
|
|
||||||
self._request('event.share', False, params)
|
self._request('event.share', False, params)
|
||||||
|
|
||||||
def get_shouts(self, limit=50):
|
def get_shouts(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequqence of Shout objects
|
Returns a sequqence of Shout objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shouts = []
|
shouts = []
|
||||||
for node in _collect_nodes(limit, self, "event.getShouts", False):
|
for node in _collect_nodes(limit, self, "event.getShouts", cacheable):
|
||||||
shouts.append(Shout(
|
shouts.append(Shout(
|
||||||
_extract(node, "body"),
|
_extract(node, "body"),
|
||||||
User(_extract(node, "author"), self.network),
|
User(_extract(node, "author"), self.network),
|
||||||
|
@ -2084,10 +2084,10 @@ class Library(_BaseObject):
|
||||||
|
|
||||||
self._request("library.addTrack", False, params)
|
self._request("library.addTrack", False, params)
|
||||||
|
|
||||||
def get_albums(self, artist=None, limit=50):
|
def get_albums(self, artist=None, limit=50, cacheable=True):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Album objects
|
Returns a sequence of Album objects
|
||||||
If no artist is specified, it will return all, sorted by playcount descendingly.
|
If no artist is specified, it will return all, sorted by decreasing play count.
|
||||||
If limit==None it will return all (may take a while)
|
If limit==None it will return all (may take a while)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -2096,7 +2096,7 @@ class Library(_BaseObject):
|
||||||
params["artist"] = artist
|
params["artist"] = artist
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "library.getAlbums", True, params):
|
for node in _collect_nodes(limit, self, "library.getAlbums", cacheable, params):
|
||||||
name = _extract(node, "name")
|
name = _extract(node, "name")
|
||||||
artist = _extract(node, "name", 1)
|
artist = _extract(node, "name", 1)
|
||||||
playcount = _number(_extract(node, "playcount"))
|
playcount = _number(_extract(node, "playcount"))
|
||||||
|
@ -2106,14 +2106,14 @@ class Library(_BaseObject):
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_artists(self, limit=50):
|
def get_artists(self, limit=50, cacheable=True):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Album objects
|
Returns a sequence of Album objects
|
||||||
if limit==None it will return all (may take a while)
|
if limit==None it will return all (may take a while)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "library.getArtists", True):
|
for node in _collect_nodes(limit, self, "library.getArtists", cacheable):
|
||||||
name = _extract(node, "name")
|
name = _extract(node, "name")
|
||||||
|
|
||||||
playcount = _number(_extract(node, "playcount"))
|
playcount = _number(_extract(node, "playcount"))
|
||||||
|
@ -2123,7 +2123,7 @@ class Library(_BaseObject):
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_tracks(self, artist=None, album=None, limit=50):
|
def get_tracks(self, artist=None, album=None, limit=50, cacheable=True):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Album objects
|
Returns a sequence of Album objects
|
||||||
If limit==None it will return all (may take a while)
|
If limit==None it will return all (may take a while)
|
||||||
|
@ -2136,7 +2136,7 @@ class Library(_BaseObject):
|
||||||
params["album"] = album
|
params["album"] = album
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "library.getTracks", True, params):
|
for node in _collect_nodes(limit, self, "library.getTracks", cacheable, params):
|
||||||
name = _extract(node, "name")
|
name = _extract(node, "name")
|
||||||
artist = _extract(node, "name", 1)
|
artist = _extract(node, "name", 1)
|
||||||
playcount = _number(_extract(node, "playcount"))
|
playcount = _number(_extract(node, "playcount"))
|
||||||
|
@ -2721,13 +2721,13 @@ class Track(_BaseObject, _Taggable):
|
||||||
|
|
||||||
return self.network._get_url(domain_name, "track") %{'domain': self.network._get_language_domain(domain_name), 'artist': artist, 'title': title}
|
return self.network._get_url(domain_name, "track") %{'domain': self.network._get_language_domain(domain_name), 'artist': artist, 'title': title}
|
||||||
|
|
||||||
def get_shouts(self, limit=50):
|
def get_shouts(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequqence of Shout objects
|
Returns a sequqence of Shout objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shouts = []
|
shouts = []
|
||||||
for node in _collect_nodes(limit, self, "track.getShouts", False):
|
for node in _collect_nodes(limit, self, "track.getShouts", cacheable):
|
||||||
shouts.append(Shout(
|
shouts.append(Shout(
|
||||||
_extract(node, "body"),
|
_extract(node, "body"),
|
||||||
User(_extract(node, "author"), self.network),
|
User(_extract(node, "author"), self.network),
|
||||||
|
@ -2854,13 +2854,13 @@ class Group(_BaseObject):
|
||||||
|
|
||||||
return self.network._get_url(domain_name, "group") %{'name': name}
|
return self.network._get_url(domain_name, "group") %{'name': name}
|
||||||
|
|
||||||
def get_members(self, limit=50):
|
def get_members(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of User objects
|
Returns a sequence of User objects
|
||||||
if limit==None it will return all
|
if limit==None it will return all
|
||||||
"""
|
"""
|
||||||
|
|
||||||
nodes = _collect_nodes(limit, self, "group.getMembers", False)
|
nodes = _collect_nodes(limit, self, "group.getMembers", cacheable)
|
||||||
|
|
||||||
users = []
|
users = []
|
||||||
|
|
||||||
|
@ -2966,7 +2966,7 @@ class User(_BaseObject):
|
||||||
|
|
||||||
return self._extract_events_from_doc(doc)
|
return self._extract_events_from_doc(doc)
|
||||||
|
|
||||||
def get_artist_tracks(self, artist):
|
def get_artist_tracks(self, artist, cacheable=False):
|
||||||
"""Get a list of tracks by a given artist scrobbled by this user, including scrobble time."""
|
"""Get a list of tracks by a given artist scrobbled by this user, including scrobble time."""
|
||||||
# Not implemented: "Can be limited to specific timeranges, defaults to all time."
|
# Not implemented: "Can be limited to specific timeranges, defaults to all time."
|
||||||
|
|
||||||
|
@ -2974,7 +2974,7 @@ class User(_BaseObject):
|
||||||
params['artist'] = artist
|
params['artist'] = artist
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for track in _collect_nodes(None, self, "user.getArtistTracks", False, params):
|
for track in _collect_nodes(None, self, "user.getArtistTracks", cacheable, params):
|
||||||
title = _extract(track, "name")
|
title = _extract(track, "name")
|
||||||
artist = _extract(track, "artist")
|
artist = _extract(track, "artist")
|
||||||
date = _extract(track, "date")
|
date = _extract(track, "date")
|
||||||
|
@ -2985,16 +2985,16 @@ class User(_BaseObject):
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_friends(self, limit = 50):
|
def get_friends(self, limit = 50, cacheable=False):
|
||||||
"""Returns a list of the user's friends. """
|
"""Returns a list of the user's friends. """
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "user.getFriends", False):
|
for node in _collect_nodes(limit, self, "user.getFriends", cacheable):
|
||||||
seq.append(User(_extract(node, "name"), self.network))
|
seq.append(User(_extract(node, "name"), self.network))
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_loved_tracks(self, limit=50):
|
def get_loved_tracks(self, limit=50, cacheable=True):
|
||||||
"""Returns this user's loved track as a sequence of LovedTrack objects
|
"""Returns this user's loved track as a sequence of LovedTrack objects
|
||||||
in reverse order of their timestamp, all the way back to the first track.
|
in reverse order of their timestamp, all the way back to the first track.
|
||||||
|
|
||||||
|
@ -3011,7 +3011,7 @@ class User(_BaseObject):
|
||||||
params['limit'] = limit
|
params['limit'] = limit
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for track in _collect_nodes(limit, self, "user.getLovedTracks", True, params):
|
for track in _collect_nodes(limit, self, "user.getLovedTracks", cacheable, params):
|
||||||
|
|
||||||
title = _extract(track, "name")
|
title = _extract(track, "name")
|
||||||
artist = _extract(track, "name", 1)
|
artist = _extract(track, "name", 1)
|
||||||
|
@ -3039,14 +3039,14 @@ class User(_BaseObject):
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_past_events(self, limit=50):
|
def get_past_events(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Event objects
|
Returns a sequence of Event objects
|
||||||
if limit==None it will return all
|
if limit==None it will return all
|
||||||
"""
|
"""
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for n in _collect_nodes(limit, self, "user.getPastEvents", False):
|
for n in _collect_nodes(limit, self, "user.getPastEvents", cacheable):
|
||||||
seq.append(Event(_extract(n, "id"), self.network))
|
seq.append(Event(_extract(n, "id"), self.network))
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
@ -3086,7 +3086,7 @@ class User(_BaseObject):
|
||||||
return Track(artist, title, self.network, self.name)
|
return Track(artist, title, self.network, self.name)
|
||||||
|
|
||||||
|
|
||||||
def get_recent_tracks(self, limit = 10):
|
def get_recent_tracks(self, limit=10, cacheable=True):
|
||||||
"""Returns this user's played track as a sequence of PlayedTrack objects
|
"""Returns this user's played track as a sequence of PlayedTrack objects
|
||||||
in reverse order of their playtime, all the way back to the first track.
|
in reverse order of their playtime, all the way back to the first track.
|
||||||
|
|
||||||
|
@ -3103,7 +3103,7 @@ class User(_BaseObject):
|
||||||
params['limit'] = limit
|
params['limit'] = limit
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for track in _collect_nodes(limit, self, "user.getRecentTracks", True, params):
|
for track in _collect_nodes(limit, self, "user.getRecentTracks", cacheable, params):
|
||||||
|
|
||||||
if track.hasAttribute('nowplaying'):
|
if track.hasAttribute('nowplaying'):
|
||||||
continue #to prevent the now playing track from sneaking in here
|
continue #to prevent the now playing track from sneaking in here
|
||||||
|
@ -3412,13 +3412,13 @@ class User(_BaseObject):
|
||||||
|
|
||||||
return Library(self, self.network)
|
return Library(self, self.network)
|
||||||
|
|
||||||
def get_shouts(self, limit=50):
|
def get_shouts(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequqence of Shout objects
|
Returns a sequqence of Shout objects
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shouts = []
|
shouts = []
|
||||||
for node in _collect_nodes(limit, self, "user.getShouts", False):
|
for node in _collect_nodes(limit, self, "user.getShouts", cacheable):
|
||||||
shouts.append(Shout(
|
shouts.append(Shout(
|
||||||
_extract(node, "body"),
|
_extract(node, "body"),
|
||||||
User(_extract(node, "author"), self.network),
|
User(_extract(node, "author"), self.network),
|
||||||
|
@ -3452,26 +3452,26 @@ class AuthenticatedUser(User):
|
||||||
self.name = _extract(doc, "name")
|
self.name = _extract(doc, "name")
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_recommended_events(self, limit=50):
|
def get_recommended_events(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Event objects
|
Returns a sequence of Event objects
|
||||||
if limit==None it will return all
|
if limit==None it will return all
|
||||||
"""
|
"""
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "user.getRecommendedEvents", False):
|
for node in _collect_nodes(limit, self, "user.getRecommendedEvents", cacheable):
|
||||||
seq.append(Event(_extract(node, "id"), self.network))
|
seq.append(Event(_extract(node, "id"), self.network))
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
def get_recommended_artists(self, limit=50):
|
def get_recommended_artists(self, limit=50, cacheable=False):
|
||||||
"""
|
"""
|
||||||
Returns a sequence of Event objects
|
Returns a sequence of Event objects
|
||||||
if limit==None it will return all
|
if limit==None it will return all
|
||||||
"""
|
"""
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in _collect_nodes(limit, self, "user.getRecommendedArtists", False):
|
for node in _collect_nodes(limit, self, "user.getRecommendedArtists", cacheable):
|
||||||
seq.append(Artist(_extract(node, "name"), self.network))
|
seq.append(Artist(_extract(node, "name"), self.network))
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
105
test_pylast.py
105
test_pylast.py
|
@ -755,6 +755,111 @@ class TestPyLast(unittest.TestCase):
|
||||||
self.assertEqual(name, "Last.fm Network")
|
self.assertEqual(name, "Last.fm Network")
|
||||||
|
|
||||||
|
|
||||||
|
def test_artist_get_images_deprecated(self):
|
||||||
|
# Arrange
|
||||||
|
artist = self.network.get_artist("Test Artist")
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
with self.assertRaisesRegexp(pylast.WSError, 'deprecated'):
|
||||||
|
artist.get_images()
|
||||||
|
|
||||||
|
|
||||||
|
def helper_validate_results(self, a, b, c):
|
||||||
|
# Assert
|
||||||
|
self.assertIsNotNone(a)
|
||||||
|
self.assertIsNotNone(b)
|
||||||
|
self.assertIsNotNone(c)
|
||||||
|
self.assertGreaterEqual(len(a), 0)
|
||||||
|
self.assertGreaterEqual(len(b), 0)
|
||||||
|
self.assertGreaterEqual(len(c), 0)
|
||||||
|
self.assertEqual(a, b)
|
||||||
|
self.assertEqual(b, c)
|
||||||
|
|
||||||
|
|
||||||
|
def helper_validate_cacheable(self, thing, function_name):
|
||||||
|
# Arrange
|
||||||
|
# get thing.function_name()
|
||||||
|
func = getattr(thing, function_name, None)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result1 = func(limit = 1, cacheable = False)
|
||||||
|
result2 = func(limit = 1, cacheable = True)
|
||||||
|
result3 = func(limit = 1)
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_validate_results(result1, result2, result3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_artist_get_shouts(self):
|
||||||
|
# Arrange
|
||||||
|
artist = self.network.get_artist("Test Artist")
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(artist, "get_shouts")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_event_get_shouts(self):
|
||||||
|
# Arrange
|
||||||
|
user = self.network.get_user("RJ")
|
||||||
|
event = user.get_past_events(limit = 1)[0]
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(event, "get_shouts")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_track_get_shouts(self):
|
||||||
|
# Arrange
|
||||||
|
track = self.network.get_top_tracks()[0]
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(track, "get_shouts")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_group_get_members(self):
|
||||||
|
# Arrange
|
||||||
|
group = self.network.get_group("Audioscrobbler Beta")
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(group, "get_members")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_library(self):
|
||||||
|
# Arrange
|
||||||
|
library = pylast.Library(self.username, self.network)
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(library, "get_albums")
|
||||||
|
self.helper_validate_cacheable(library, "get_artists")
|
||||||
|
self.helper_validate_cacheable(library, "get_tracks")
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_user_artist_tracks(self):
|
||||||
|
# Arrange
|
||||||
|
lastfm_user = self.network.get_authenticated_user()
|
||||||
|
|
||||||
|
# Act
|
||||||
|
result1 = lastfm_user.get_artist_tracks(artist = "Test Artist", cacheable = False)
|
||||||
|
result2 = lastfm_user.get_artist_tracks(artist = "Test Artist", cacheable = True)
|
||||||
|
result3 = lastfm_user.get_artist_tracks(artist = "Test Artist")
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.helper_validate_results(result1, result2, result3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cacheable_user(self):
|
||||||
|
# Arrange
|
||||||
|
lastfm_user = self.network.get_authenticated_user()
|
||||||
|
|
||||||
|
# Act/Assert
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_friends")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_loved_tracks")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_past_events")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_recent_tracks")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_recommended_artists")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_recommended_events")
|
||||||
|
self.helper_validate_cacheable(lastfm_user, "get_shouts")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
# For quick testing of a single case (eg. test = "test_scrobble")
|
# For quick testing of a single case (eg. test = "test_scrobble")
|
||||||
|
|
Loading…
Reference in a new issue