Merge pull request #264 from pylast/save-artist-images
Save artist images and refactor album images
This commit is contained in:
commit
fad76315bb
|
@ -133,5 +133,5 @@ network = pylast.LastFMNetwork(...)
|
||||||
To enable from pytest:
|
To enable from pytest:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pytest -k test_album_search_images --log-cli-level debug
|
pytest --log-cli-level debug -k test_album_search_images
|
||||||
```
|
```
|
||||||
|
|
|
@ -903,7 +903,7 @@ class SessionKeyGenerator(object):
|
||||||
a. network = get_*_network(API_KEY, API_SECRET)
|
a. network = get_*_network(API_KEY, API_SECRET)
|
||||||
b. sg = SessionKeyGenerator(network)
|
b. sg = SessionKeyGenerator(network)
|
||||||
c. url = sg.get_web_auth_url()
|
c. url = sg.get_web_auth_url()
|
||||||
d. Ask the user to open the url and authorize you, and wait for it.
|
d. Ask the user to open the URL and authorize you, and wait for it.
|
||||||
e. session_key = sg.get_web_auth_session_key(url)
|
e. session_key = sg.get_web_auth_session_key(url)
|
||||||
2) Username and Password Authentication:
|
2) Username and Password Authentication:
|
||||||
a. network = get_*_network(API_KEY, API_SECRET)
|
a. network = get_*_network(API_KEY, API_SECRET)
|
||||||
|
@ -961,7 +961,7 @@ class SessionKeyGenerator(object):
|
||||||
|
|
||||||
def get_web_auth_session_key(self, url, token=""):
|
def get_web_auth_session_key(self, url, token=""):
|
||||||
"""
|
"""
|
||||||
Retrieves the session key of a web authorization process by its url.
|
Retrieves the session key of a web authorization process by its URL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if url in self.web_auth_tokens.keys():
|
if url in self.web_auth_tokens.keys():
|
||||||
|
@ -1375,7 +1375,7 @@ class _Opus(_BaseObject, _Taggable):
|
||||||
__hash__ = _BaseObject.__hash__
|
__hash__ = _BaseObject.__hash__
|
||||||
|
|
||||||
def __init__(self, artist, title, network, ws_prefix, username=None,
|
def __init__(self, artist, title, network, ws_prefix, username=None,
|
||||||
images=None):
|
info=None):
|
||||||
"""
|
"""
|
||||||
Create an opus instance.
|
Create an opus instance.
|
||||||
# Parameters:
|
# Parameters:
|
||||||
|
@ -1384,6 +1384,9 @@ class _Opus(_BaseObject, _Taggable):
|
||||||
* ws_prefix: 'album' or 'track'
|
* ws_prefix: 'album' or 'track'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if info is None:
|
||||||
|
info = {}
|
||||||
|
|
||||||
_BaseObject.__init__(self, network, ws_prefix)
|
_BaseObject.__init__(self, network, ws_prefix)
|
||||||
_Taggable.__init__(self, ws_prefix)
|
_Taggable.__init__(self, ws_prefix)
|
||||||
|
|
||||||
|
@ -1394,7 +1397,7 @@ class _Opus(_BaseObject, _Taggable):
|
||||||
|
|
||||||
self.title = title
|
self.title = title
|
||||||
self.username = username
|
self.username = username
|
||||||
self.images = images
|
self.info = info
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "pylast.%s(%s, %s, %s)" % (
|
return "pylast.%s(%s, %s, %s)" % (
|
||||||
|
@ -1428,6 +1431,21 @@ class _Opus(_BaseObject, _Taggable):
|
||||||
|
|
||||||
return self.artist
|
return self.artist
|
||||||
|
|
||||||
|
def get_cover_image(self, size=SIZE_EXTRA_LARGE):
|
||||||
|
"""
|
||||||
|
Returns a URI to the cover image
|
||||||
|
size can be one of:
|
||||||
|
SIZE_EXTRA_LARGE
|
||||||
|
SIZE_LARGE
|
||||||
|
SIZE_MEDIUM
|
||||||
|
SIZE_SMALL
|
||||||
|
"""
|
||||||
|
if "image" not in self.info:
|
||||||
|
self.info["image"] = _extract_all(
|
||||||
|
self._request(self.ws_prefix + ".getInfo", cacheable=True),
|
||||||
|
"image")
|
||||||
|
return self.info["image"][size]
|
||||||
|
|
||||||
def get_title(self, properly_capitalized=False):
|
def get_title(self, properly_capitalized=False):
|
||||||
"""Returns the artist or track title."""
|
"""Returns the artist or track title."""
|
||||||
if properly_capitalized:
|
if properly_capitalized:
|
||||||
|
@ -1492,24 +1510,9 @@ class Album(_Opus):
|
||||||
|
|
||||||
__hash__ = _Opus.__hash__
|
__hash__ = _Opus.__hash__
|
||||||
|
|
||||||
def __init__(self, artist, title, network, username=None, images=None):
|
def __init__(self, artist, title, network, username=None, info=None):
|
||||||
super(Album, self).__init__(artist, title, network, "album", username,
|
super(Album, self).__init__(artist, title, network, "album", username,
|
||||||
images)
|
info)
|
||||||
|
|
||||||
def get_cover_image(self, size=SIZE_EXTRA_LARGE):
|
|
||||||
"""
|
|
||||||
Returns a uri to the cover image
|
|
||||||
size can be one of:
|
|
||||||
SIZE_EXTRA_LARGE
|
|
||||||
SIZE_LARGE
|
|
||||||
SIZE_MEDIUM
|
|
||||||
SIZE_SMALL
|
|
||||||
"""
|
|
||||||
if not self.images:
|
|
||||||
self.images = _extract_all(
|
|
||||||
self._request(self.ws_prefix + ".getInfo", cacheable=True),
|
|
||||||
'image')
|
|
||||||
return self.images[size]
|
|
||||||
|
|
||||||
def get_tracks(self):
|
def get_tracks(self):
|
||||||
"""Returns the list of Tracks on this album."""
|
"""Returns the list of Tracks on this album."""
|
||||||
|
@ -1552,17 +1555,21 @@ class Artist(_BaseObject, _Taggable):
|
||||||
|
|
||||||
__hash__ = _BaseObject.__hash__
|
__hash__ = _BaseObject.__hash__
|
||||||
|
|
||||||
def __init__(self, name, network, username=None):
|
def __init__(self, name, network, username=None, info=None):
|
||||||
"""Create an artist object.
|
"""Create an artist object.
|
||||||
# Parameters:
|
# Parameters:
|
||||||
* name str: The artist's name.
|
* name str: The artist's name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if info is None:
|
||||||
|
info = {}
|
||||||
|
|
||||||
_BaseObject.__init__(self, network, 'artist')
|
_BaseObject.__init__(self, network, 'artist')
|
||||||
_Taggable.__init__(self, 'artist')
|
_Taggable.__init__(self, 'artist')
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.username = username
|
self.username = username
|
||||||
|
self.info = info
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "pylast.Artist(%s, %s)" % (
|
return "pylast.Artist(%s, %s)" % (
|
||||||
|
@ -1606,7 +1613,7 @@ class Artist(_BaseObject, _Taggable):
|
||||||
|
|
||||||
def get_cover_image(self, size=SIZE_EXTRA_LARGE):
|
def get_cover_image(self, size=SIZE_EXTRA_LARGE):
|
||||||
"""
|
"""
|
||||||
Returns a uri to the cover image
|
Returns a URI to the cover image
|
||||||
size can be one of:
|
size can be one of:
|
||||||
SIZE_MEGA
|
SIZE_MEGA
|
||||||
SIZE_EXTRA_LARGE
|
SIZE_EXTRA_LARGE
|
||||||
|
@ -1615,8 +1622,11 @@ class Artist(_BaseObject, _Taggable):
|
||||||
SIZE_SMALL
|
SIZE_SMALL
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return _extract_all(
|
if "image" not in self.info:
|
||||||
self._request(self.ws_prefix + ".getInfo", True), "image")[size]
|
self.info["image"] = _extract_all(
|
||||||
|
self._request(self.ws_prefix + ".getInfo", cacheable=True),
|
||||||
|
"image")
|
||||||
|
return self.info["image"][size]
|
||||||
|
|
||||||
def get_playcount(self):
|
def get_playcount(self):
|
||||||
"""Returns the number of plays on the network."""
|
"""Returns the number of plays on the network."""
|
||||||
|
@ -1724,7 +1734,7 @@ class Artist(_BaseObject, _Taggable):
|
||||||
"getTopTracks", "track", Track, params, cacheable)
|
"getTopTracks", "track", Track, params, cacheable)
|
||||||
|
|
||||||
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.
|
||||||
# Parameters:
|
# Parameters:
|
||||||
* domain_name: The network's language domain. Possible values:
|
* domain_name: The network's language domain. Possible values:
|
||||||
o DOMAIN_ENGLISH
|
o DOMAIN_ENGLISH
|
||||||
|
@ -1800,7 +1810,7 @@ class Country(_BaseObject):
|
||||||
"getTopTracks", "track", Track, params, cacheable)
|
"getTopTracks", "track", Track, params, cacheable)
|
||||||
|
|
||||||
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.
|
||||||
* domain_name: The network's language domain. Possible values:
|
* domain_name: The network's language domain. Possible values:
|
||||||
o DOMAIN_ENGLISH
|
o DOMAIN_ENGLISH
|
||||||
o DOMAIN_GERMAN
|
o DOMAIN_GERMAN
|
||||||
|
@ -1945,7 +1955,7 @@ class Tag(_BaseObject, _Chartable):
|
||||||
return _extract_top_artists(doc, self.network)
|
return _extract_top_artists(doc, self.network)
|
||||||
|
|
||||||
def get_url(self, domain_name=DOMAIN_ENGLISH):
|
def get_url(self, domain_name=DOMAIN_ENGLISH):
|
||||||
"""Returns the url of the tag page on the network.
|
"""Returns the URL of the tag page on the network.
|
||||||
* domain_name: The network's language domain. Possible values:
|
* domain_name: The network's language domain. Possible values:
|
||||||
o DOMAIN_ENGLISH
|
o DOMAIN_ENGLISH
|
||||||
o DOMAIN_GERMAN
|
o DOMAIN_GERMAN
|
||||||
|
@ -1971,8 +1981,9 @@ class Track(_Opus):
|
||||||
|
|
||||||
__hash__ = _Opus.__hash__
|
__hash__ = _Opus.__hash__
|
||||||
|
|
||||||
def __init__(self, artist, title, network, username=None):
|
def __init__(self, artist, title, network, username=None, info=None):
|
||||||
super(Track, self).__init__(artist, title, network, "track", username)
|
super(Track, self).__init__(artist, title, network, "track", username,
|
||||||
|
info)
|
||||||
|
|
||||||
def get_correction(self):
|
def get_correction(self):
|
||||||
"""Returns the corrected track name."""
|
"""Returns the corrected track name."""
|
||||||
|
@ -2454,7 +2465,7 @@ class User(_BaseObject, _Chartable):
|
||||||
return _extract_all(doc, "image")[size]
|
return _extract_all(doc, "image")[size]
|
||||||
|
|
||||||
def get_url(self, domain_name=DOMAIN_ENGLISH):
|
def get_url(self, domain_name=DOMAIN_ENGLISH):
|
||||||
"""Returns the url of the user page on the network.
|
"""Returns the URL of the user page on the network.
|
||||||
* domain_name: The network's language domain. Possible values:
|
* domain_name: The network's language domain. Possible values:
|
||||||
o DOMAIN_ENGLISH
|
o DOMAIN_ENGLISH
|
||||||
o DOMAIN_GERMAN
|
o DOMAIN_GERMAN
|
||||||
|
@ -2550,11 +2561,14 @@ class AlbumSearch(_Search):
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in master_node.getElementsByTagName("album"):
|
for node in master_node.getElementsByTagName("album"):
|
||||||
seq.append(Album(
|
seq.append(
|
||||||
|
Album(
|
||||||
_extract(node, "artist"),
|
_extract(node, "artist"),
|
||||||
_extract(node, "name"),
|
_extract(node, "name"),
|
||||||
self.network,
|
self.network,
|
||||||
images=_extract_all(node, 'image')))
|
info={"image": _extract_all(node, "image")},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
|
@ -2572,7 +2586,11 @@ class ArtistSearch(_Search):
|
||||||
|
|
||||||
seq = []
|
seq = []
|
||||||
for node in master_node.getElementsByTagName("artist"):
|
for node in master_node.getElementsByTagName("artist"):
|
||||||
artist = Artist(_extract(node, "name"), self.network)
|
artist = Artist(
|
||||||
|
_extract(node, "name"),
|
||||||
|
self.network,
|
||||||
|
info={"image": _extract_all(node, "image")},
|
||||||
|
)
|
||||||
artist.listener_count = _number(_extract(node, "listeners"))
|
artist.listener_count = _number(_extract(node, "listeners"))
|
||||||
seq.append(artist)
|
seq.append(artist)
|
||||||
|
|
||||||
|
@ -2603,7 +2621,9 @@ class TrackSearch(_Search):
|
||||||
track = Track(
|
track = Track(
|
||||||
_extract(node, "artist"),
|
_extract(node, "artist"),
|
||||||
_extract(node, "name"),
|
_extract(node, "name"),
|
||||||
self.network)
|
self.network,
|
||||||
|
info={"image": _extract_all(node, "image")},
|
||||||
|
)
|
||||||
track.listener_count = _number(_extract(node, "listeners"))
|
track.listener_count = _number(_extract(node, "listeners"))
|
||||||
seq.append(track)
|
seq.append(track)
|
||||||
|
|
||||||
|
@ -2767,7 +2787,7 @@ def _extract_tracks(doc, network):
|
||||||
|
|
||||||
|
|
||||||
def _url_safe(text):
|
def _url_safe(text):
|
||||||
"""Does all kinds of tricks on a text to make it safe to use in a url."""
|
"""Does all kinds of tricks on a text to make it safe to use in a URL."""
|
||||||
|
|
||||||
return url_quote_plus(url_quote_plus(_string(text))).lower()
|
return url_quote_plus(url_quote_plus(_string(text))).lower()
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastAlbum(PyLastTestCase):
|
class TestPyLastAlbum(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_album_tags_are_topitems(self):
|
def test_album_tags_are_topitems(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -107,8 +107,8 @@ class TestPyLastAlbum(PyLastTestCase):
|
||||||
image = album.get_cover_image()
|
image = album.get_cover_image()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(image.startswith("https://"))
|
self.assert_startswith(image, "https://")
|
||||||
self.assertTrue(image.endswith(".png"))
|
self.assert_endswith(image, ".png")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastArtist(PyLastTestCase):
|
class TestPyLastArtist(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastCountry(PyLastTestCase):
|
class TestPyLastCountry(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_country_is_hashable(self):
|
def test_country_is_hashable(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastLibrary(PyLastTestCase):
|
class TestPyLastLibrary(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -19,7 +19,7 @@ class TestPyLastLibrary(PyLastTestCase):
|
||||||
representation = repr(library)
|
representation = repr(library)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(representation.startswith("pylast.Library("))
|
self.assert_startswith(representation, "pylast.Library(")
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -29,7 +29,7 @@ class TestPyLastLibrary(PyLastTestCase):
|
||||||
string = str(library)
|
string = str(library)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(string.endswith("'s Library"))
|
self.assert_endswith(string, "'s Library")
|
||||||
|
|
||||||
def test_library_is_hashable(self):
|
def test_library_is_hashable(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -8,11 +8,11 @@ from flaky import flaky
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import load_secrets
|
from .test_pylast import PyLastTestCase, load_secrets
|
||||||
|
|
||||||
|
|
||||||
@flaky(max_runs=5, min_passes=1)
|
@flaky(max_runs=3, min_passes=1)
|
||||||
class TestPyLastWithLibreFm(unittest.TestCase):
|
class TestPyLastWithLibreFm(PyLastTestCase):
|
||||||
"""Own class for Libre.fm because we don't need the Last.fm setUp"""
|
"""Own class for Libre.fm because we don't need the Last.fm setUp"""
|
||||||
|
|
||||||
def test_libre_fm(self):
|
def test_libre_fm(self):
|
||||||
|
@ -42,7 +42,7 @@ class TestPyLastWithLibreFm(unittest.TestCase):
|
||||||
representation = repr(network)
|
representation = repr(network)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(representation.startswith("pylast.LibreFMNetwork("))
|
self.assert_startswith(representation, "pylast.LibreFMNetwork(")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -7,10 +7,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastNetwork(PyLastTestCase):
|
class TestPyLastNetwork(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_scrobble(self):
|
def test_scrobble(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -322,17 +322,17 @@ class TestPyLastNetwork(PyLastTestCase):
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
results = search.get_next_page()
|
results = search.get_next_page()
|
||||||
images = results[0].images
|
images = results[0].info["image"]
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertEqual(len(images), 4)
|
self.assertEqual(len(images), 4)
|
||||||
|
|
||||||
self.assertTrue(images[pylast.SIZE_SMALL].startswith("https://"))
|
self.assert_startswith(images[pylast.SIZE_SMALL], "https://")
|
||||||
self.assertTrue(images[pylast.SIZE_SMALL].endswith(".png"))
|
self.assert_endswith(images[pylast.SIZE_SMALL], ".png")
|
||||||
self.assertIn("/34s/", images[pylast.SIZE_SMALL])
|
self.assertIn("/34s/", images[pylast.SIZE_SMALL])
|
||||||
|
|
||||||
self.assertTrue(images[pylast.SIZE_EXTRA_LARGE].startswith("https://"))
|
self.assert_startswith(images[pylast.SIZE_EXTRA_LARGE], "https://")
|
||||||
self.assertTrue(images[pylast.SIZE_EXTRA_LARGE].endswith(".png"))
|
self.assert_endswith(images[pylast.SIZE_EXTRA_LARGE], ".png")
|
||||||
self.assertIn("/300x300/", images[pylast.SIZE_EXTRA_LARGE])
|
self.assertIn("/300x300/", images[pylast.SIZE_EXTRA_LARGE])
|
||||||
|
|
||||||
def test_artist_search(self):
|
def test_artist_search(self):
|
||||||
|
@ -347,6 +347,26 @@ class TestPyLastNetwork(PyLastTestCase):
|
||||||
self.assertIsInstance(results, list)
|
self.assertIsInstance(results, list)
|
||||||
self.assertIsInstance(results[0], pylast.Artist)
|
self.assertIsInstance(results[0], pylast.Artist)
|
||||||
|
|
||||||
|
def test_artist_search_images(self):
|
||||||
|
# Arrange
|
||||||
|
artist = "Nirvana"
|
||||||
|
search = self.network.search_for_artist(artist)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
results = search.get_next_page()
|
||||||
|
images = results[0].info["image"]
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(len(images), 5)
|
||||||
|
|
||||||
|
self.assert_startswith(images[pylast.SIZE_SMALL], "https://")
|
||||||
|
self.assert_endswith(images[pylast.SIZE_SMALL], ".png")
|
||||||
|
self.assertIn("/34s/", images[pylast.SIZE_SMALL])
|
||||||
|
|
||||||
|
self.assert_startswith(images[pylast.SIZE_EXTRA_LARGE], "https://")
|
||||||
|
self.assert_endswith(images[pylast.SIZE_EXTRA_LARGE], ".png")
|
||||||
|
self.assertIn("/300x300/", images[pylast.SIZE_EXTRA_LARGE])
|
||||||
|
|
||||||
def test_track_search(self):
|
def test_track_search(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
artist = "Nirvana"
|
artist = "Nirvana"
|
||||||
|
@ -360,6 +380,27 @@ class TestPyLastNetwork(PyLastTestCase):
|
||||||
self.assertIsInstance(results, list)
|
self.assertIsInstance(results, list)
|
||||||
self.assertIsInstance(results[0], pylast.Track)
|
self.assertIsInstance(results[0], pylast.Track)
|
||||||
|
|
||||||
|
def test_track_search_images(self):
|
||||||
|
# Arrange
|
||||||
|
artist = "Nirvana"
|
||||||
|
track = "Smells Like Teen Spirit"
|
||||||
|
search = self.network.search_for_track(artist, track)
|
||||||
|
|
||||||
|
# Act
|
||||||
|
results = search.get_next_page()
|
||||||
|
images = results[0].info["image"]
|
||||||
|
|
||||||
|
# Assert
|
||||||
|
self.assertEqual(len(images), 4)
|
||||||
|
|
||||||
|
self.assert_startswith(images[pylast.SIZE_SMALL], "https://")
|
||||||
|
self.assert_endswith(images[pylast.SIZE_SMALL], ".png")
|
||||||
|
self.assertIn("/34s/", images[pylast.SIZE_SMALL])
|
||||||
|
|
||||||
|
self.assert_startswith(images[pylast.SIZE_EXTRA_LARGE], "https://")
|
||||||
|
self.assert_endswith(images[pylast.SIZE_EXTRA_LARGE], ".png")
|
||||||
|
self.assertIn("/300x300/", images[pylast.SIZE_EXTRA_LARGE])
|
||||||
|
|
||||||
def test_search_get_total_result_count(self):
|
def test_search_get_total_result_count(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
artist = "Nirvana"
|
artist = "Nirvana"
|
||||||
|
|
|
@ -30,9 +30,18 @@ def load_secrets():
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|
||||||
@flaky(max_runs=5, min_passes=1)
|
|
||||||
class PyLastTestCase(unittest.TestCase):
|
class PyLastTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def assert_startswith(self, str, prefix, start=None, end=None):
|
||||||
|
self.assertTrue(str.startswith(prefix, start, end))
|
||||||
|
|
||||||
|
def assert_endswith(self, str, suffix, start=None, end=None):
|
||||||
|
self.assertTrue(str.endswith(suffix, start, end))
|
||||||
|
|
||||||
|
|
||||||
|
@flaky(max_runs=3, min_passes=1)
|
||||||
|
class TestPyLastWithLastFm(PyLastTestCase):
|
||||||
|
|
||||||
secrets = None
|
secrets = None
|
||||||
|
|
||||||
def unix_timestamp(self):
|
def unix_timestamp(self):
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastTag(PyLastTestCase):
|
class TestPyLastTag(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_tag_is_hashable(self):
|
def test_tag_is_hashable(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -6,10 +6,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastTrack(PyLastTestCase):
|
class TestPyLastTrack(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_love(self):
|
def test_love(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -7,10 +7,10 @@ import unittest
|
||||||
|
|
||||||
import pylast
|
import pylast
|
||||||
|
|
||||||
from .test_pylast import PyLastTestCase
|
from .test_pylast import TestPyLastWithLastFm
|
||||||
|
|
||||||
|
|
||||||
class TestPyLastUser(PyLastTestCase):
|
class TestPyLastUser(TestPyLastWithLastFm):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -20,7 +20,7 @@ class TestPyLastUser(PyLastTestCase):
|
||||||
representation = repr(user)
|
representation = repr(user)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(representation.startswith("pylast.User('RJ',"))
|
self.assert_startswith(representation, "pylast.User('RJ',")
|
||||||
|
|
||||||
def test_str(self):
|
def test_str(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -342,7 +342,7 @@ class TestPyLastUser(PyLastTestCase):
|
||||||
url = user.get_image()
|
url = user.get_image()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(url.startswith("https://"))
|
self.assert_startswith(url, "https://")
|
||||||
|
|
||||||
def test_user_get_library(self):
|
def test_user_get_library(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
@ -392,8 +392,8 @@ class TestPyLastUser(PyLastTestCase):
|
||||||
image = user.get_image()
|
image = user.get_image()
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
self.assertTrue(image.startswith("https://"))
|
self.assert_startswith(image, "https://")
|
||||||
self.assertTrue(image.endswith(".png"))
|
self.assert_endswith(image, ".png")
|
||||||
|
|
||||||
def test_get_url(self):
|
def test_get_url(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
Loading…
Reference in a new issue