def albums(self): """The albums matching the search query. Will always return an empty list if the search isn't loaded. """ spotify.Error.maybe_raise( self.error, ignores=[spotify.ErrorType.IS_LOADING] ) if not self.is_loaded: return [] @serialized def get_album(sp_search, key): return spotify.Album( self._session, sp_album=lib.sp_search_album(sp_search, key), add_ref=True, ) return utils.Sequence( sp_obj=self._sp_search, add_ref_func=lib.sp_search_add_ref, release_func=lib.sp_search_release, len_func=lib.sp_search_num_albums, getitem_func=get_album, )
def playlists(self): """The playlists matching the search query as :class:`SearchPlaylist` objects containing the name, URI and image URI for matching playlists. Will always return an empty list if the search isn't loaded. """ spotify.Error.maybe_raise( self.error, ignores=[spotify.ErrorType.IS_LOADING] ) if not self.is_loaded: return [] @serialized def getitem(sp_search, key): return spotify.SearchPlaylist( self._session, name=utils.to_unicode( lib.sp_search_playlist_name(self._sp_search, key) ), uri=utils.to_unicode( lib.sp_search_playlist_uri(self._sp_search, key) ), image_uri=utils.to_unicode( lib.sp_search_playlist_image_uri(self._sp_search, key) ), ) return utils.Sequence( sp_obj=self._sp_search, add_ref_func=lib.sp_search_add_ref, release_func=lib.sp_search_release, len_func=lib.sp_search_num_playlists, getitem_func=getitem, )
def test_getitem_with_slice(self, lib_mock): sp_search = spotify.ffi.cast('sp_search *', 42) getitem_func = mock.Mock() getitem_func.side_effect = [ mock.sentinel.item_one, mock.sentinel.item_two, mock.sentinel.item_three, ] seq = utils.Sequence( sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 3, getitem_func=getitem_func, ) result = seq[0:2] # Entire collection of length 3 is created as a list self.assertEqual(getitem_func.call_count, 3) # Only a subslice of length 2 is returned self.assertIsInstance(result, list) self.assertEqual(len(result), 2) self.assertEqual(result[0], mock.sentinel.item_one) self.assertEqual(result[1], mock.sentinel.item_two)
def portraits(self, callback=None): """The artist's portraits. Due to limitations in libspotify's API you can't specify the :class:`ImageSize` of these images. If ``callback`` isn't :class:`None`, it is expected to be a callable that accepts a single argument, an :class:`Image` instance, when the image is done loading. The callable will be called once for each portrait. Will always return an empty list if the artist browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_image(sp_artistbrowse, key): image_id = lib.sp_artistbrowse_portrait(sp_artistbrowse, key) sp_image = lib.sp_image_create(image_id) return spotify.Image(self._session, sp_image=sp_image, add_ref=False, callback=callback) return utils.Sequence(sp_obj=self._sp_artistbrowse, add_ref_func=lib.sp_artistbrowse_add_ref, release_func=lib.sp_artistbrowse_release, len_func=lib.sp_artistbrowse_num_portraits, getitem_func=get_image)
def artists(self): """The artists performing on the track. Will always return an empty list if the track isn't loaded. """ spotify.Error.maybe_raise(self.error, ignores=[spotify.ErrorType.IS_LOADING]) if not self.is_loaded: return [] @serialized def get_artist(sp_track, key): return spotify.Artist( self._session, sp_artist=lib.sp_track_artist(sp_track, key), add_ref=True, ) return utils.Sequence( sp_obj=self._sp_track, add_ref_func=lib.sp_track_add_ref, release_func=lib.sp_track_release, len_func=lib.sp_track_num_artists, getitem_func=get_artist, )
def test_adds_ref_to_sp_obj_when_created(self, lib_mock): sp_search = spotify.ffi.new('int *') utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=None, getitem_func=None) self.assertEqual(lib_mock.sp_search_add_ref.call_count, 1)
def test_getitem_raises_type_error_on_non_integral_index(self, lib_mock): sp_search = spotify.ffi.new('int *') seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=None) with self.assertRaises(TypeError): seq['abc']
def test_getitem_raises_index_error_on_too_high_index(self, lib_mock): sp_search = spotify.ffi.new('int *') seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=None) with self.assertRaises(IndexError): seq[1]
def test_repr(self, lib_mock): sp_search = spotify.ffi.new('int *') seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=lambda s, i: 123) result = repr(seq) self.assertEqual(result, '[123]')
def test_getitem_raises_index_error_on_too_low_index(self, lib_mock): sp_search = spotify.ffi.cast('sp_search *', 42) seq = utils.Sequence( sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=None, ) with self.assertRaises(IndexError): seq[-3]
def test_releases_sp_obj_when_sequence_dies(self, lib_mock): sp_search = spotify.ffi.new('int *') seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=None, getitem_func=None) seq = None # noqa tests.gc_collect() self.assertEqual(lib_mock.sp_search_release.call_count, 1)
def test_repr(self, lib_mock): sp_search = spotify.ffi.cast('sp_search *', 42) seq = utils.Sequence( sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=lambda s, i: 123, ) result = repr(seq) self.assertEqual(result, 'Sequence([123])')
def test_getitem_with_negative_index(self, lib_mock): sp_search = spotify.ffi.cast('sp_search *', 42) getitem_func = mock.Mock() getitem_func.return_value = mock.sentinel.item_one seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=getitem_func) result = seq[-1] self.assertEqual(result, mock.sentinel.item_one) getitem_func.assert_called_with(sp_search, 0)
def test_getitem_calls_getitem_func(self, lib_mock): sp_search = spotify.ffi.new('int *') getitem_func = mock.Mock() getitem_func.return_value = mock.sentinel.item_one seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=lambda x: 1, getitem_func=getitem_func) result = seq[0] self.assertEqual(result, mock.sentinel.item_one) getitem_func.assert_called_with(sp_search, 0)
def test_len_calls_len_func(self, lib_mock): sp_search = spotify.ffi.new('int *') len_func = mock.Mock() len_func.return_value = 0 seq = utils.Sequence(sp_obj=sp_search, add_ref_func=lib_mock.sp_search_add_ref, release_func=lib_mock.sp_search_release, len_func=len_func, getitem_func=None) result = len(seq) self.assertEqual(result, 0) len_func.assert_called_with(sp_search)
def copyrights(self): """The album's copyright strings. Will always return an empty list if the album browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_copyright(sp_albumbrowse, key): return utils.to_unicode( lib.sp_albumbrowse_copyright(sp_albumbrowse, key)) return utils.Sequence(sp_obj=self._sp_albumbrowse, add_ref_func=lib.sp_albumbrowse_add_ref, release_func=lib.sp_albumbrowse_release, len_func=lib.sp_albumbrowse_num_copyrights, getitem_func=get_copyright)
def portraits(self): """The artist's portraits. Will always return an empty list if the artist browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_image(sp_artistbrowse, key): image_id = lib.sp_artistbrowse_portrait(sp_artistbrowse, key) sp_image = lib.sp_image_create(image_id) return spotify.Image(sp_image=sp_image, add_ref=False) return utils.Sequence(sp_obj=self._sp_artistbrowse, add_ref_func=lib.sp_artistbrowse_add_ref, release_func=lib.sp_artistbrowse_release, len_func=lib.sp_artistbrowse_num_portraits, getitem_func=get_image)
def artists(self): """The artists performing on the track. Will always return :class:`None` if the track isn't loaded. """ spotify.Error.maybe_raise(self.error) if not self.is_loaded: return [] @serialized def get_artist(sp_track, key): return spotify.Artist(sp_artist=lib.sp_track_artist(sp_track, key), add_ref=True) return utils.Sequence(sp_obj=self._sp_track, add_ref_func=lib.sp_track_add_ref, release_func=lib.sp_track_release, len_func=lib.sp_track_num_artists, getitem_func=get_artist)
def tophit_tracks(self): """The artist's top hit tracks. Will always return an empty list if the artist browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_track(sp_artistbrowse, key): return spotify.Track(sp_track=lib.sp_artistbrowse_tophit_track( sp_artistbrowse, key), add_ref=True) return utils.Sequence(sp_obj=self._sp_artistbrowse, add_ref_func=lib.sp_artistbrowse_add_ref, release_func=lib.sp_artistbrowse_release, len_func=lib.sp_artistbrowse_num_tophit_tracks, getitem_func=get_track)
def similar_artists(self): """The artist's similar artists. Will always return an empty list if the artist browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_artist(sp_artistbrowse, key): return spotify.Artist(sp_artist=lib.sp_artistbrowse_similar_artist( sp_artistbrowse, key), add_ref=True) return utils.Sequence(sp_obj=self._sp_artistbrowse, add_ref_func=lib.sp_artistbrowse_add_ref, release_func=lib.sp_artistbrowse_release, len_func=lib.sp_artistbrowse_num_similar_artists, getitem_func=get_artist)
def artists(self): """The artists in the toplist. Will always return an empty list if the toplist isn't loaded. """ spotify.Error.maybe_raise(self.error) if not self.is_loaded: return [] @serialized def get_artist(sp_toplistbrowse, key): return spotify.Artist(sp_artist=lib.sp_toplistbrowse_artist( sp_toplistbrowse, key), add_ref=True) return utils.Sequence(sp_obj=self._sp_toplistbrowse, add_ref_func=lib.sp_toplistbrowse_add_ref, release_func=lib.sp_toplistbrowse_release, len_func=lib.sp_toplistbrowse_num_artists, getitem_func=get_artist)
def albums(self): """The artist's albums. Will be an empty list if the browser was created with a ``type`` of :attr:`ArtistBrowserType.NO_ALBUMS`. Will always return an empty list if the artist browser isn't loaded. """ if not self.is_loaded: return [] @serialized def get_album(sp_artistbrowse, key): return spotify.Album(sp_album=lib.sp_artistbrowse_album( sp_artistbrowse, key), add_ref=True) return utils.Sequence(sp_obj=self._sp_artistbrowse, add_ref_func=lib.sp_artistbrowse_add_ref, release_func=lib.sp_artistbrowse_release, len_func=lib.sp_artistbrowse_num_albums, getitem_func=get_album)
def tracks(self): """The tracks in the toplist. Will always return an empty list if the toplist isn't loaded. """ spotify.Error.maybe_raise(self.error) if not self.is_loaded: return [] @serialized def get_track(sp_toplistbrowse, key): return spotify.Track( self._session, sp_track=lib.sp_toplistbrowse_track(sp_toplistbrowse, key), add_ref=True, ) return utils.Sequence( sp_obj=self._sp_toplistbrowse, add_ref_func=lib.sp_toplistbrowse_add_ref, release_func=lib.sp_toplistbrowse_release, len_func=lib.sp_toplistbrowse_num_tracks, getitem_func=get_track, )