From 78f71794e17418604105800c385b02b289e5bf83 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 9 Aug 2010 12:05:08 +0200 Subject: [PATCH] Fix tests broken by knutz3n's search improvements, and sync GstreamerBackend's find_exact() and search() --- mopidy/backends/__init__.py | 26 +++++++++---- mopidy/backends/despotify.py | 5 ++- mopidy/backends/gstreamer.py | 66 ++++++++++++++++++++++----------- tests/backends/base.py | 72 ++++++++++++++++++------------------ 4 files changed, 103 insertions(+), 66 deletions(-) diff --git a/mopidy/backends/__init__.py b/mopidy/backends/__init__.py index fb3b03d3..e9f6b4c5 100644 --- a/mopidy/backends/__init__.py +++ b/mopidy/backends/__init__.py @@ -283,12 +283,21 @@ class BaseLibraryController(object): """Cleanup after component.""" pass - def find_exact(self, query): + def find_exact(self, **query): """ - Find tracks in the library where ``field`` matches ``what`` exactly. + Search the library for tracks where ``field`` is ``values``. - :param query: Example: [(u'artist', u'anArtist'), (u'album', u'anAlbum')] - :type query: list of (field, what) tuples. + Examples:: + + # Returns results matching 'a' + find_exact(any=['a']) + # Returns results matching artist 'xyz' + find_exact(artist=['xyz']) + # Returns results matching 'a' and 'b' and artist 'xyz' + find_exact(any=['a', 'b'], artist=['xyz']) + + :param query: one or more queries to search for + :type query: dict :rtype: :class:`mopidy.models.Playlist` """ raise NotImplementedError @@ -318,9 +327,12 @@ class BaseLibraryController(object): Examples:: - search(any=['a']) # Returns results matching 'a' - search(artist=['xyz']) # Returns results matching artist 'xyz' - search(any=['a', 'b'], artist=['xyz']) # Returns results matching 'a' and 'b' and artist 'xyz' + # Returns results matching 'a' + search(any=['a']) + # Returns results matching artist 'xyz' + search(artist=['xyz']) + # Returns results matching 'a' and 'b' and artist 'xyz' + search(any=['a', 'b'], artist=['xyz']) :param query: one or more queries to search for :type query: dict diff --git a/mopidy/backends/despotify.py b/mopidy/backends/despotify.py index 17281ab5..251fd8bb 100644 --- a/mopidy/backends/despotify.py +++ b/mopidy/backends/despotify.py @@ -53,6 +53,9 @@ class DespotifyCurrentPlaylistController(BaseCurrentPlaylistController): class DespotifyLibraryController(BaseLibraryController): + def find_exact(self, **query): + self.search(**query) + def lookup(self, uri): track = self.backend.spotify.lookup(uri.encode(ENCODING)) return DespotifyTranslator.to_mopidy_track(track) @@ -76,8 +79,6 @@ class DespotifyLibraryController(BaseLibraryController): return Playlist() return DespotifyTranslator.to_mopidy_playlist(result.playlist) - find_exact = search - class DespotifyPlaybackController(BasePlaybackController): def _pause(self): diff --git a/mopidy/backends/gstreamer.py b/mopidy/backends/gstreamer.py index 41d81150..3bb089e5 100644 --- a/mopidy/backends/gstreamer.py +++ b/mopidy/backends/gstreamer.py @@ -217,38 +217,55 @@ class GStreamerLibraryController(BaseLibraryController): except KeyError: raise LookupError('%s not found.' % uri) - def find_exact(self, query): - for (field, what) in query: - if not what: - raise LookupError('Missing query') - + def find_exact(self, **query): + self._validate_query(query) result_tracks = self._uri_mapping.values() - for (field, what) in query: - if field == 'track': - filter_func = lambda t: t.name == what - elif field == 'album': - filter_func = lambda t: getattr(t, 'album', Album()).name == what - elif field == 'artist': - filter_func = lambda t: filter(lambda a: a.name == what, t.artists) - else: - raise LookupError('Invalid lookup field: %s' % field) - result_tracks = filter(filter_func, result_tracks) + for (field, values) in query.iteritems(): + if not hasattr(values, '__iter__'): + values = [values] + # FIXME this is bound to be slow for large libraries + for value in values: + q = value.strip() + + track_filter = lambda t: q == t.name + album_filter = lambda t: q == getattr(t, 'album', Album()).name + artist_filter = lambda t: filter( + lambda a: q == a.name, t.artists) + uri_filter = lambda t: q == t.uri + any_filter = lambda t: (track_filter(t) or album_filter(t) or + artist_filter(t) or uri_filter(t)) + + if field == 'track': + result_tracks = filter(track_filter, result_tracks) + elif field == 'album': + result_tracks = filter(album_filter, result_tracks) + elif field == 'artist': + result_tracks = filter(artist_filter, result_tracks) + elif field == 'uri': + result_tracks = filter(uri_filter, result_tracks) + elif field == 'any': + result_tracks = filter(any_filter, result_tracks) + else: + raise LookupError('Invalid lookup field: %s' % field) return Playlist(tracks=result_tracks) def search(self, **query): + self._validate_query(query) result_tracks = self._uri_mapping.values() - for (field, values) in query: + + for (field, values) in query.iteritems(): if not hasattr(values, '__iter__'): values = [values] + # FIXME this is bound to be slow for large libraries for value in values: q = value.strip().lower() - # FIXME this is bound to be slow for large libraries track_filter = lambda t: q in t.name.lower() - album_filter = lambda t: q in getattr(t, 'album', Album()).name.lower() - artist_filter = lambda t: filter(lambda a: q in a.name.lower(), - t.artists) + album_filter = lambda t: q in getattr( + t, 'album', Album()).name.lower() + artist_filter = lambda t: filter( + lambda a: q in a.name.lower(), t.artists) uri_filter = lambda t: q in t.uri.lower() any_filter = lambda t: track_filter(t) or album_filter(t) or \ artist_filter(t) or uri_filter(t) @@ -265,5 +282,12 @@ class GStreamerLibraryController(BaseLibraryController): result_tracks = filter(any_filter, result_tracks) else: raise LookupError('Invalid lookup field: %s' % field) - return Playlist(tracks=result_tracks) + + def _validate_query(self, query): + for (field, values) in query.iteritems(): + if not values: + raise LookupError('Missing query') + for value in values: + if not value: + raise LookupError('Missing query') diff --git a/tests/backends/base.py b/tests/backends/base.py index ecb4c693..416c1799 100644 --- a/tests/backends/base.py +++ b/tests/backends/base.py @@ -1079,120 +1079,120 @@ class BaseLibraryControllerTest(object): self.assertRaises(LookupError, test) def test_find_exact_no_hits(self): - result = self.library.find_exact([('track', 'unknown track')]) + result = self.library.find_exact(track=['unknown track']) self.assertEqual(result, Playlist()) - result = self.library.find_exact([('artist', 'unknown artist')]) + result = self.library.find_exact(artist=['unknown artist']) self.assertEqual(result, Playlist()) - result = self.library.find_exact([('album', 'unknown artist')]) + result = self.library.find_exact(album=['unknown artist']) self.assertEqual(result, Playlist()) def test_find_exact_artist(self): - result = self.library.find_exact([('artist', 'artist1')]) + result = self.library.find_exact(artist=['artist1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.find_exact([('artist', 'artist2')]) + result = self.library.find_exact(artist=['artist2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_find_exact_track(self): - result = self.library.find_exact([('track', 'track1')]) + result = self.library.find_exact(track=['track1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.find_exact([('track', 'track2')]) + result = self.library.find_exact(track=['track2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_find_exact_album(self): - result = self.library.find_exact([('album', 'album1')]) + result = self.library.find_exact(album=['album1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.find_exact([('album', 'album2')]) + result = self.library.find_exact(album=['album2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_find_exact_wrong_type(self): - test = lambda: self.library.find_exact([('wrong', 'test')]) + test = lambda: self.library.find_exact(wrong=['test']) self.assertRaises(LookupError, test) def test_find_exact_with_empty_query(self): - test = lambda: self.library.find_exact([('artist', '')]) + test = lambda: self.library.find_exact(artist=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.find_exact([('track', '')]) + test = lambda: self.library.find_exact(track=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.find_exact([('album', '')]) + test = lambda: self.library.find_exact(album=['']) self.assertRaises(LookupError, test) def test_search_no_hits(self): - result = self.library.search([('track', 'unknown track')]) + result = self.library.search(track=['unknown track']) self.assertEqual(result, Playlist()) - result = self.library.search([('artist', 'unknown artist')]) + result = self.library.search(artist=['unknown artist']) self.assertEqual(result, Playlist()) - result = self.library.search([('album', 'unknown artist')]) + result = self.library.search(album=['unknown artist']) self.assertEqual(result, Playlist()) - result = self.library.search([('uri', 'unknown')]) + result = self.library.search(uri=['unknown']) self.assertEqual(result, Playlist()) - result = self.library.search([('any', 'unknown')]) + result = self.library.search(any=['unknown']) self.assertEqual(result, Playlist()) def test_search_artist(self): - result = self.library.search([('artist', 'Tist1')]) + result = self.library.search(artist=['Tist1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('artist', 'Tist2')]) + result = self.library.search(artist=['Tist2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_search_track(self): - result = self.library.search([('track', 'Rack1')]) + result = self.library.search(track=['Rack1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('track', 'Rack2')]) + result = self.library.search(track=['Rack2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_search_album(self): - result = self.library.search([('album', 'Bum1')]) + result = self.library.search(album=['Bum1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('album', 'Bum2')]) + result = self.library.search(album=['Bum2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_search_uri(self): - result = self.library.search([('uri', 'RI1')]) + result = self.library.search(uri=['RI1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('uri', 'RI2')]) + result = self.library.search(uri=['RI2']) self.assertEqual(result, Playlist(tracks=self.tracks[1:2])) def test_search_any(self): - result = self.library.search([('any', 'Tist1')]) + result = self.library.search(any=['Tist1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('any', 'Rack1')]) + result = self.library.search(any=['Rack1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('any', 'Bum1')]) + result = self.library.search(any=['Bum1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) - result = self.library.search([('any', 'RI1')]) + result = self.library.search(any=['RI1']) self.assertEqual(result, Playlist(tracks=self.tracks[:1])) def test_search_wrong_type(self): - test = lambda: self.library.search([('wrong', 'test')]) + test = lambda: self.library.search(wrong=['test']) self.assertRaises(LookupError, test) def test_search_with_empty_query(self): - test = lambda: self.library.search([('artist', '')]) + test = lambda: self.library.search(artist=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.search([('track', '')]) + test = lambda: self.library.search(track=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.search([('album', '')]) + test = lambda: self.library.search(album=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.search([('uri', '')]) + test = lambda: self.library.search(uri=['']) self.assertRaises(LookupError, test) - test = lambda: self.library.search([('any', '')]) + test = lambda: self.library.search(any=['']) self.assertRaises(LookupError, test)