Added option to stream from resources to reduce memory usage

This commit is contained in:
kvanzuijlen 2020-07-12 11:54:46 +02:00 committed by Koen van Zuijlen
parent 705052ae66
commit 92004058ba
8 changed files with 174 additions and 192 deletions

View file

@ -103,7 +103,7 @@ export PYLAST_API_SECRET=TODO_ENTER_YOURS_HERE
To run all unit and integration tests: To run all unit and integration tests:
```sh ```sh
pip install pytest flaky pip install .[tests]
pytest pytest
``` ```

View file

@ -1149,21 +1149,22 @@ class _BaseObject:
return first_child.wholeText.strip() return first_child.wholeText.strip()
def _get_things(self, method, thing, thing_type, params=None, cacheable=True): def _get_things(self, method, thing, thing_type, params=None, cacheable=True, stream=False):
"""Returns a list of the most played thing_types by this thing.""" """Returns a list of the most played thing_types by this thing."""
def _stream_get_things():
limit = params.get("limit", 1) limit = params.get("limit", 1)
seq = [] nodes = _collect_nodes(
for node in _collect_nodes( limit, self, self.ws_prefix + "." + method, cacheable, params, stream=stream,
limit, self, self.ws_prefix + "." + method, cacheable, params )
): for node in nodes:
title = _extract(node, "name") title = _extract(node, "name")
artist = _extract(node, "name", 1) artist = _extract(node, "name", 1)
playcount = _number(_extract(node, "playcount")) playcount = _number(_extract(node, "playcount"))
seq.append(TopItem(thing_type(artist, title, self.network), playcount)) yield TopItem(thing_type(artist, title, self.network), playcount)
return seq return _stream_get_things() if stream else list(_stream_get_things())
def get_wiki_published_date(self): def get_wiki_published_date(self):
""" """
@ -1835,21 +1836,21 @@ class Artist(_BaseObject, _Taggable):
return artists return artists
def get_top_albums(self, limit=None, cacheable=True): def get_top_albums(self, limit=None, cacheable=True, stream=True):
"""Returns a list of the top albums.""" """Returns a list of the top albums."""
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit params["limit"] = limit
return self._get_things("getTopAlbums", "album", Album, params, cacheable) return self._get_things("getTopAlbums", "album", Album, params, cacheable, stream=stream)
def get_top_tracks(self, limit=None, cacheable=True): def get_top_tracks(self, limit=None, cacheable=True, stream=True):
"""Returns a list of the most played Tracks by this artist.""" """Returns a list of the most played Tracks by this artist."""
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit params["limit"] = limit
return self._get_things("getTopTracks", "track", Track, params, cacheable) return self._get_things("getTopTracks", "track", Track, params, cacheable, stream=stream)
def get_url(self, domain_name=DOMAIN_ENGLISH): def get_url(self, domain_name=DOMAIN_ENGLISH):
"""Returns the URL of the artist page on the network. """Returns the URL of the artist page on the network.
@ -1917,13 +1918,13 @@ class Country(_BaseObject):
return _extract_top_artists(doc, self) return _extract_top_artists(doc, self)
def get_top_tracks(self, limit=None, cacheable=True): def get_top_tracks(self, limit=None, cacheable=True, stream=True):
"""Returns a sequence of the most played tracks""" """Returns a sequence of the most played tracks"""
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit params["limit"] = limit
return self._get_things("getTopTracks", "track", Track, params, cacheable) return self._get_things("getTopTracks", "track", Track, params, cacheable, stream=stream)
def get_url(self, domain_name=DOMAIN_ENGLISH): def get_url(self, domain_name=DOMAIN_ENGLISH):
"""Returns the URL of the country page on the network. """Returns the URL of the country page on the network.
@ -1978,24 +1979,24 @@ class Library(_BaseObject):
"""Returns the user who owns this library.""" """Returns the user who owns this library."""
return self.user return self.user
def get_artists(self, limit=50, cacheable=True): def get_artists(self, limit=50, cacheable=True, stream=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 = [] def _get_artists():
for node in _collect_nodes( for node in _collect_nodes(
limit, self, self.ws_prefix + ".getArtists", cacheable limit, self, self.ws_prefix + ".getArtists", cacheable, stream=stream
): ):
name = _extract(node, "name") name = _extract(node, "name")
playcount = _number(_extract(node, "playcount")) playcount = _number(_extract(node, "playcount"))
tagcount = _number(_extract(node, "tagcount")) tagcount = _number(_extract(node, "tagcount"))
seq.append(LibraryItem(Artist(name, self.network), playcount, tagcount)) yield LibraryItem(Artist(name, self.network), playcount, tagcount)
return seq return _get_artists() if stream else list(_get_artists())
class Tag(_BaseObject, _Chartable): class Tag(_BaseObject, _Chartable):
@ -2047,13 +2048,13 @@ class Tag(_BaseObject, _Chartable):
return _extract_top_albums(doc, self.network) return _extract_top_albums(doc, self.network)
def get_top_tracks(self, limit=None, cacheable=True): def get_top_tracks(self, limit=None, cacheable=True, stream=True):
"""Returns a list of the most played Tracks for this tag.""" """Returns a list of the most played Tracks for this tag."""
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit params["limit"] = limit
return self._get_things("getTopTracks", "track", Track, params, cacheable) return self._get_things("getTopTracks", "track", Track, params, cacheable, stream=stream)
def get_top_artists(self, limit=None, cacheable=True): def get_top_artists(self, limit=None, cacheable=True):
"""Returns a sequence of the most played artists.""" """Returns a sequence of the most played artists."""
@ -2241,6 +2242,14 @@ class User(_BaseObject, _Chartable):
def _get_params(self): def _get_params(self):
return {self.ws_prefix: self.get_name()} return {self.ws_prefix: self.get_name()}
def _extract_played_track(self, track_node):
title = _extract(track_node, "name")
track_artist = _extract(track_node, "artist")
date = _extract(track_node, "date")
album = _extract(track_node, "album")
timestamp = track_node.getElementsByTagName("date")[0].getAttribute("uts")
return PlayedTrack(Track(track_artist, title, self.network), album, date, timestamp)
def get_name(self, properly_capitalized=False): def get_name(self, properly_capitalized=False):
"""Returns the user name.""" """Returns the user name."""
@ -2251,7 +2260,7 @@ class User(_BaseObject, _Chartable):
return self.name return self.name
def get_artist_tracks(self, artist, cacheable=False): def get_artist_tracks(self, artist, cacheable=False, stream=True):
""" """
Deprecated by Last.fm. Deprecated by Last.fm.
Get a list of tracks by a given artist scrobbled by this user, Get a list of tracks by a given artist scrobbled by this user,
@ -2269,51 +2278,44 @@ class User(_BaseObject, _Chartable):
params = self._get_params() params = self._get_params()
params["artist"] = artist params["artist"] = artist
seq = [] def _get_artist_tracks():
for track in _collect_nodes( for track_node in _collect_nodes(
None, self, self.ws_prefix + ".getArtistTracks", cacheable, params None, self, self.ws_prefix + ".getArtistTracks", cacheable, params, stream=stream,
): ):
title = _extract(track, "name") yield self._extract_played_track(track_node=track_node)
artist = _extract(track, "artist")
date = _extract(track, "date")
album = _extract(track, "album")
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
seq.append( return _get_artist_tracks() if stream else list(_get_artist_tracks())
PlayedTrack(Track(artist, title, self.network), album, date, timestamp)
)
return seq def get_friends(self, limit=50, cacheable=False, stream=True):
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 = [] def _get_friends():
for node in _collect_nodes( for node in _collect_nodes(
limit, self, self.ws_prefix + ".getFriends", cacheable limit, self, self.ws_prefix + ".getFriends", cacheable, stream=stream
): ):
seq.append(User(_extract(node, "name"), self.network)) yield User(_extract(node, "name"), self.network)
return seq return _get_friends() if stream else list(_get_friends())
def get_loved_tracks(self, limit=50, cacheable=True): def get_loved_tracks(self, limit=50, cacheable=True, stream=True):
""" """
Returns this user's loved track as a sequence of LovedTrack objects in 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. reverse order of their timestamp, all the way back to the first track.
If limit==None, it will try to pull all the available data. If limit==None, it will try to pull all the available data.
If stream=True, it will yield tracks as soon as a page has been retrieved.
This method uses caching. Enable caching only if you're pulling a This method uses caching. Enable caching only if you're pulling a
large amount of data. large amount of data.
""" """
def _get_loved_tracks():
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit params["limit"] = limit
seq = []
for track in _collect_nodes( for track in _collect_nodes(
limit, self, self.ws_prefix + ".getLovedTracks", cacheable, params limit, self, self.ws_prefix + ".getLovedTracks", cacheable, params, stream=stream
): ):
try: try:
artist = _extract(track, "name", 1) artist = _extract(track, "name", 1)
@ -2323,9 +2325,9 @@ class User(_BaseObject, _Chartable):
date = _extract(track, "date") date = _extract(track, "date")
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts") timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
seq.append(LovedTrack(Track(artist, title, self.network), date, timestamp)) yield LovedTrack(Track(artist, title, self.network), date, timestamp)
return seq return _get_loved_tracks() if stream else list(_get_loved_tracks())
def get_now_playing(self): def get_now_playing(self):
""" """
@ -2353,7 +2355,7 @@ class User(_BaseObject, _Chartable):
return Track(artist, title, self.network, self.name, info=info) return Track(artist, title, self.network, self.name, info=info)
def get_recent_tracks(self, limit=10, cacheable=True, time_from=None, time_to=None): def get_recent_tracks(self, limit=10, cacheable=True, time_from=None, time_to=None, stream=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 playtime, all the way back to the first track. in reverse order of playtime, all the way back to the first track.
@ -2368,11 +2370,13 @@ class User(_BaseObject, _Chartable):
before this time, in UNIX timestamp format (integer number of before this time, in UNIX timestamp format (integer number of
seconds since 00:00:00, January 1st 1970 UTC). This must be in seconds since 00:00:00, January 1st 1970 UTC). This must be in
the UTC time zone. the UTC time zone.
stream: If True, it will yield tracks as soon as a page has been retrieved.
This method uses caching. Enable caching only if you're pulling a This method uses caching. Enable caching only if you're pulling a
large amount of data. large amount of data.
""" """
def _get_recent_tracks():
params = self._get_params() params = self._get_params()
if limit: if limit:
params["limit"] = limit + 1 # in case we remove the now playing track params["limit"] = limit + 1 # in case we remove the now playing track
@ -2381,32 +2385,20 @@ class User(_BaseObject, _Chartable):
if time_to: if time_to:
params["to"] = time_to params["to"] = time_to
seq = [] for track_node in _collect_nodes(
for track in _collect_nodes(
limit + 1 if limit else None, limit + 1 if limit else None,
self, self,
self.ws_prefix + ".getRecentTracks", self.ws_prefix + ".getRecentTracks",
cacheable, cacheable,
params, params,
stream=stream
): ):
if track_node.hasAttribute("nowplaying"):
if track.hasAttribute("nowplaying"):
continue # to prevent the now playing track from sneaking in continue # to prevent the now playing track from sneaking in
title = _extract(track, "name") yield self._extract_played_track(track_node=track_node)
artist = _extract(track, "artist")
date = _extract(track, "date")
album = _extract(track, "album")
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
seq.append( return _get_recent_tracks() if stream else list(_get_recent_tracks())
PlayedTrack(Track(artist, title, self.network), album, date, timestamp)
)
if limit:
# Slice, in case we didn't remove a now playing track
seq = seq[:limit]
return seq
def get_country(self): def get_country(self):
"""Returns the name of the country of the user.""" """Returns the name of the country of the user."""
@ -2545,7 +2537,7 @@ class User(_BaseObject, _Chartable):
return seq return seq
def get_top_tracks(self, period=PERIOD_OVERALL, limit=None, cacheable=True): def get_top_tracks(self, period=PERIOD_OVERALL, limit=None, cacheable=True, stream=True):
"""Returns the top tracks played by a user. """Returns the top tracks played by a user.
* period: The period of time. Possible values: * period: The period of time. Possible values:
o PERIOD_OVERALL o PERIOD_OVERALL
@ -2561,33 +2553,24 @@ class User(_BaseObject, _Chartable):
if limit: if limit:
params["limit"] = limit params["limit"] = limit
return self._get_things("getTopTracks", "track", Track, params, cacheable) return self._get_things("getTopTracks", "track", Track, params, cacheable, stream=stream)
def get_track_scrobbles(self, artist, track, cacheable=False): def get_track_scrobbles(self, artist, track, cacheable=False, stream=True):
""" """
Get a list of this user's scrobbles of this artist's track, Get a list of this user's scrobbles of this artist's track,
including scrobble time. including scrobble time.
""" """
params = self._get_params() params = self._get_params()
params["artist"] = artist params["artist"] = artist
params["track"] = track params["track"] = track
seq = [] def _get_track_scrobbles():
for track in _collect_nodes( for track_node in _collect_nodes(
None, self, self.ws_prefix + ".getTrackScrobbles", cacheable, params None, self, self.ws_prefix + ".getTrackScrobbles", cacheable, params, stream=stream
): ):
title = _extract(track, "name") yield self._extract_played_track(track_node)
artist = _extract(track, "artist")
date = _extract(track, "date")
album = _extract(track, "album")
timestamp = track.getElementsByTagName("date")[0].getAttribute("uts")
seq.append( return _get_track_scrobbles() if stream else list(_get_track_scrobbles())
PlayedTrack(Track(artist, title, self.network), album, date, timestamp)
)
return seq
def get_image(self, size=SIZE_EXTRA_LARGE): def get_image(self, size=SIZE_EXTRA_LARGE):
""" """
@ -2797,19 +2780,19 @@ def cleanup_nodes(doc):
return doc return doc
def _collect_nodes(limit, sender, method_name, cacheable, params=None): def _collect_nodes(limit, sender, method_name, cacheable, params=None, stream=False):
""" """
Returns a sequence of dom.Node objects about as close to limit as possible Returns a sequence of dom.Node objects about as close to limit as possible
""" """
if not params: if not params:
params = sender._get_params() params = sender._get_params()
nodes = [] def _stream_collect_nodes():
node_count = 0
page = 1 page = 1
end_of_pages = False end_of_pages = False
while not end_of_pages and (not limit or (limit and len(nodes) < limit)): while not end_of_pages and (not limit or (limit and node_count < limit)):
params["page"] = str(page) params["page"] = str(page)
tries = 1 tries = 1
@ -2831,25 +2814,23 @@ def _collect_nodes(limit, sender, method_name, cacheable, params=None):
break break
main = doc.documentElement.childNodes[0] main = doc.documentElement.childNodes[0]
if main.hasAttribute("totalPages"): if main.hasAttribute("totalPages") or main.hasAttribute("totalpages"):
total_pages = _number(main.getAttribute("totalPages")) total_pages = _number(main.getAttribute("totalPages") or main.getAttribute("totalpages"))
elif main.hasAttribute("totalpages"):
total_pages = _number(main.getAttribute("totalpages"))
else: else:
raise Exception("No total pages attribute") raise Exception("No total pages attribute")
for node in main.childNodes: for node in main.childNodes:
if not node.nodeType == xml.dom.Node.TEXT_NODE and ( if not node.nodeType == xml.dom.Node.TEXT_NODE and (
not limit or (len(nodes) < limit) not limit or (node_count < limit)
): ):
nodes.append(node) node_count += 1
yield node
if page >= total_pages: end_of_pages = page >= total_pages
end_of_pages = True
page += 1 page += 1
return nodes return _stream_collect_nodes() if stream else list(_stream_collect_nodes())
def _extract(node, name, index=0): def _extract(node, name, index=0):

View file

@ -32,7 +32,7 @@ class TestPyLastAlbum(TestPyLastWithLastFm):
# Act # Act
# limit=2 to ignore now-playing: # limit=2 to ignore now-playing:
track = lastfm_user.get_recent_tracks(limit=2)[0] track = list(lastfm_user.get_recent_tracks(limit=2))[0]
# Assert # Assert
assert hasattr(track, "album") assert hasattr(track, "album")

View file

@ -2,9 +2,9 @@
""" """
Integration (not unit) tests for pylast.py Integration (not unit) tests for pylast.py
""" """
import pylast
import pytest import pytest
import pylast
from .test_pylast import WRITE_TEST, TestPyLastWithLastFm from .test_pylast import WRITE_TEST, TestPyLastWithLastFm
@ -78,7 +78,7 @@ class TestPyLastArtist(TestPyLastWithLastFm):
artist = self.network.get_top_artists(limit=1)[0].item artist = self.network.get_top_artists(limit=1)[0].item
# Act # Act
things = artist.get_top_tracks(limit=2) things = artist.get_top_tracks(limit=2, stream=False)
# Assert # Assert
self.helper_two_different_things_in_top_list(things, pylast.Track) self.helper_two_different_things_in_top_list(things, pylast.Track)
@ -89,7 +89,7 @@ class TestPyLastArtist(TestPyLastWithLastFm):
artist = self.network.get_top_artists(limit=1)[0].item artist = self.network.get_top_artists(limit=1)[0].item
# Act # Act
things = artist.get_top_albums(limit=2) things = list(artist.get_top_albums(limit=2))
# Assert # Assert
self.helper_two_different_things_in_top_list(things, pylast.Album) self.helper_two_different_things_in_top_list(things, pylast.Album)
@ -101,7 +101,7 @@ class TestPyLastArtist(TestPyLastWithLastFm):
artist = self.network.get_top_artists(limit=1)[0].item artist = self.network.get_top_artists(limit=1)[0].item
# Act # Act
things = artist.get_top_albums(limit=limit) things = artist.get_top_albums(limit=limit, stream=False)
# Assert # Assert
assert len(things) == 1 assert len(things) == 1
@ -113,7 +113,7 @@ class TestPyLastArtist(TestPyLastWithLastFm):
artist = self.network.get_top_artists(limit=1)[0].item artist = self.network.get_top_artists(limit=1)[0].item
# Act # Act
things = artist.get_top_albums(limit=limit) things = artist.get_top_albums(limit=limit, stream=False)
# Assert # Assert
assert len(things) == 50 assert len(things) == 50
@ -125,7 +125,7 @@ class TestPyLastArtist(TestPyLastWithLastFm):
artist = self.network.get_top_artists(limit=1)[0].item artist = self.network.get_top_artists(limit=1)[0].item
# Act # Act
things = artist.get_top_albums(limit=limit) things = list(artist.get_top_albums(limit=limit))
# Assert # Assert
assert len(things) == 100 assert len(things) == 100

View file

@ -5,9 +5,9 @@ Integration (not unit) tests for pylast.py
import re import re
import time import time
import pylast
import pytest import pytest
import pylast
from .test_pylast import WRITE_TEST, TestPyLastWithLastFm from .test_pylast import WRITE_TEST, TestPyLastWithLastFm
@ -26,7 +26,7 @@ class TestPyLastNetwork(TestPyLastWithLastFm):
# Assert # Assert
# limit=2 to ignore now-playing: # limit=2 to ignore now-playing:
last_scrobble = lastfm_user.get_recent_tracks(limit=2)[0] last_scrobble = list(lastfm_user.get_recent_tracks(limit=2))[0]
assert str(last_scrobble.track.artist).lower() == artist assert str(last_scrobble.track.artist).lower() == artist
assert str(last_scrobble.track.title).lower() == title assert str(last_scrobble.track.title).lower() == title
@ -153,7 +153,7 @@ class TestPyLastNetwork(TestPyLastWithLastFm):
country = self.network.get_country("Croatia") country = self.network.get_country("Croatia")
# Act # Act
things = country.get_top_tracks(limit=2) things = country.get_top_tracks(limit=2, stream=False)
# Assert # Assert
self.helper_two_different_things_in_top_list(things, pylast.Track) self.helper_two_different_things_in_top_list(things, pylast.Track)
@ -171,7 +171,7 @@ class TestPyLastNetwork(TestPyLastWithLastFm):
tag = self.network.get_tag("blues") tag = self.network.get_tag("blues")
# Act # Act
things = tag.get_top_tracks(limit=2) things = tag.get_top_tracks(limit=2, stream=False)
# Assert # Assert
self.helper_two_different_things_in_top_list(things, pylast.Track) self.helper_two_different_things_in_top_list(things, pylast.Track)

View file

@ -6,10 +6,11 @@ import os
import sys import sys
import time import time
import pylast
import pytest import pytest
from flaky import flaky from flaky import flaky
import pylast
WRITE_TEST = sys.version_info[:2] == (3, 8) WRITE_TEST = sys.version_info[:2] == (3, 8)
@ -82,9 +83,9 @@ class TestPyLastWithLastFm(PyLastTestCase):
assert a is not None assert a is not None
assert b is not None assert b is not None
assert c is not None assert c is not None
assert len(a) >= 0 assert isinstance(len(a), int)
assert len(b) >= 0 assert isinstance(len(b), int)
assert len(c) >= 0 assert isinstance(len(c), int)
assert a == b assert a == b
assert b == c assert b == c
@ -94,9 +95,9 @@ class TestPyLastWithLastFm(PyLastTestCase):
func = getattr(thing, function_name, None) func = getattr(thing, function_name, None)
# Act # Act
result1 = func(limit=1, cacheable=False) result1 = func(limit=1, cacheable=False, stream=False)
result2 = func(limit=1, cacheable=True) result2 = func(limit=1, cacheable=True, stream=False)
result3 = func(limit=1) result3 = list(func(limit=1))
# Assert # Assert
self.helper_validate_results(result1, result2, result3) self.helper_validate_results(result1, result2, result3)

View file

@ -4,9 +4,9 @@ Integration (not unit) tests for pylast.py
""" """
import time import time
import pylast
import pytest import pytest
import pylast
from .test_pylast import WRITE_TEST, TestPyLastWithLastFm from .test_pylast import WRITE_TEST, TestPyLastWithLastFm
@ -23,7 +23,7 @@ class TestPyLastTrack(TestPyLastWithLastFm):
track.love() track.love()
# Assert # Assert
loved = lastfm_user.get_loved_tracks(limit=1) loved = list(lastfm_user.get_loved_tracks(limit=1))
assert str(loved[0].track.artist).lower() == "test artist" assert str(loved[0].track.artist).lower() == "test artist"
assert str(loved[0].track.title).lower() == "test title" assert str(loved[0].track.title).lower() == "test title"
@ -41,7 +41,7 @@ class TestPyLastTrack(TestPyLastWithLastFm):
time.sleep(1) # Delay, for Last.fm latency. TODO Can this be removed later? time.sleep(1) # Delay, for Last.fm latency. TODO Can this be removed later?
# Assert # Assert
loved = lastfm_user.get_loved_tracks(limit=1) loved = list(lastfm_user.get_loved_tracks(limit=1))
if len(loved): # OK to be empty but if not: if len(loved): # OK to be empty but if not:
assert str(loved[0].track.artist) != "Test Artist" assert str(loved[0].track.artist) != "Test Artist"
assert str(loved[0].track.title) != "test title" assert str(loved[0].track.title) != "test title"
@ -79,7 +79,7 @@ class TestPyLastTrack(TestPyLastWithLastFm):
def test_track_is_hashable(self): def test_track_is_hashable(self):
# Arrange # Arrange
artist = self.network.get_artist("Test Artist") artist = self.network.get_artist("Test Artist")
track = artist.get_top_tracks()[0].item track = artist.get_top_tracks(stream=False)[0].item
assert isinstance(track, pylast.Track) assert isinstance(track, pylast.Track)
# Act/Assert # Act/Assert

View file

@ -8,9 +8,9 @@ import os
import re import re
import warnings import warnings
import pylast
import pytest import pytest
import pylast
from .test_pylast import TestPyLastWithLastFm from .test_pylast import TestPyLastWithLastFm
@ -142,10 +142,10 @@ class TestPyLastUser(TestPyLastWithLastFm):
user = self.network.get_user("test-user") user = self.network.get_user("test-user")
# Act/Assert # Act/Assert
assert len(user.get_loved_tracks(limit=20)) == 20 assert len(user.get_loved_tracks(limit=20, stream=False)) == 20
assert len(user.get_loved_tracks(limit=100)) <= 100 assert len(user.get_loved_tracks(limit=100, stream=False)) <= 100
assert len(user.get_loved_tracks(limit=None)) >= 23 assert len(user.get_loved_tracks(limit=None, stream=False)) >= 23
assert len(user.get_loved_tracks(limit=0)) >= 23 assert len(user.get_loved_tracks(limit=0, stream=False)) >= 23
def test_user_is_hashable(self): def test_user_is_hashable(self):
# Arrange # Arrange
@ -210,7 +210,7 @@ class TestPyLastUser(TestPyLastWithLastFm):
lastfm_user = self.network.get_user("RJ") lastfm_user = self.network.get_user("RJ")
# Act # Act
things = lastfm_user.get_top_tracks(limit=2) things = lastfm_user.get_top_tracks(limit=2, stream=False)
# Assert # Assert
self.helper_two_different_things_in_top_list(things, pylast.Track) self.helper_two_different_things_in_top_list(things, pylast.Track)
@ -361,7 +361,7 @@ class TestPyLastUser(TestPyLastWithLastFm):
utc_end = calendar.timegm(end.utctimetuple()) utc_end = calendar.timegm(end.utctimetuple())
# Act # Act
tracks = lastfm_user.get_recent_tracks(time_from=utc_start, time_to=utc_end) tracks = lastfm_user.get_recent_tracks(time_from=utc_start, time_to=utc_end, stream=False)
# Assert # Assert
assert len(tracks) == 1 assert len(tracks) == 1
@ -379,7 +379,7 @@ class TestPyLastUser(TestPyLastWithLastFm):
# Act # Act
tracks = lastfm_user.get_recent_tracks( tracks = lastfm_user.get_recent_tracks(
time_from=utc_start, time_to=utc_end, limit=None time_from=utc_start, time_to=utc_end, limit=None, stream=False
) )
# Assert # Assert
@ -449,7 +449,7 @@ class TestPyLastUser(TestPyLastWithLastFm):
user = self.network.get_user("bbc6music") user = self.network.get_user("bbc6music")
# Act # Act
scrobbles = user.get_track_scrobbles(artist, title) scrobbles = user.get_track_scrobbles(artist, title, stream=False)
# Assert # Assert
assert len(scrobbles) > 0 assert len(scrobbles) > 0
@ -463,9 +463,9 @@ class TestPyLastUser(TestPyLastWithLastFm):
user = self.network.get_user("bbc6music") user = self.network.get_user("bbc6music")
# Act # Act
result1 = user.get_track_scrobbles(artist, title, cacheable=False) result1 = user.get_track_scrobbles(artist, title, cacheable=False, stream=False)
result2 = user.get_track_scrobbles(artist, title, cacheable=True) result2 = list(user.get_track_scrobbles(artist, title, cacheable=True))
result3 = user.get_track_scrobbles(artist, title) result3 = list(user.get_track_scrobbles(artist, title))
# Assert # Assert
self.helper_validate_results(result1, result2, result3) self.helper_validate_results(result1, result2, result3)
@ -480,4 +480,4 @@ class TestPyLastUser(TestPyLastWithLastFm):
match="Deprecated - This type of request is no longer supported", match="Deprecated - This type of request is no longer supported",
): ):
warnings.filterwarnings("ignore", category=DeprecationWarning) warnings.filterwarnings("ignore", category=DeprecationWarning)
lastfm_user.get_artist_tracks(artist="Test Artist") lastfm_user.get_artist_tracks(artist="Test Artist", stream=False)