core/backend: Remove find_exact from backends

Functionality has been replaced with an `exact` param in the search method.
Backends that still implement find_exact will continue being called via
the old method for now.
This commit is contained in:
Thomas Adamcik 2015-03-23 23:55:03 +01:00
parent 636d8f1115
commit 24fe242d56
4 changed files with 75 additions and 47 deletions

View File

@ -138,6 +138,11 @@ v1.0.0 (UNRELEASED)
- Remove :attr:`mopidy.backend.PlaylistsProvider.playlists` property.
- Removed ``find_exact`` from :class:`mopidy.backend.LibraryProvider` and
added an ``exact`` param to :meth:`mopidy.backend.LibraryProvider.search`
to replace the old code path. Core will continue supporting backends that
have not upgraded for now.
**Commands**
- Make the ``mopidy`` command print a friendly error message if the

View File

@ -119,15 +119,6 @@ class LibraryProvider(object):
result[uri] = [models.Image(uri=u) for u in image_uris]
return result
# TODO: replace with search(query, exact=True, ...)
def find_exact(self, query=None, uris=None):
"""
See :meth:`mopidy.core.LibraryController.find_exact`.
*MAY be implemented by subclass.*
"""
pass
def lookup(self, uri):
"""
See :meth:`mopidy.core.LibraryController.lookup`.
@ -144,11 +135,14 @@ class LibraryProvider(object):
"""
pass
def search(self, query=None, uris=None):
def search(self, query=None, uris=None, exact=False):
"""
See :meth:`mopidy.core.LibraryController.search`.
*MAY be implemented by subclass.*
.. versionadded:: 1.0
The ``exact`` param which replaces the old ``find_exact``.
"""
pass

View File

@ -160,6 +160,12 @@ class LibraryController(object):
{'any': ['a']}, uris=['file:///media/music', 'spotify:'])
find_exact(any=['a'], uris=['file:///media/music', 'spotify:'])
.. versionchanged:: 1.0
This method now calls
:meth:`~mopidy.backend.LibraryProvider.search` on the backends
instead of the deprecated ``find_exact``. If the backend still
implements ``find_exact`` we will continue to use it for now.
:param query: one or more queries to search for
:type query: dict
:param uris: zero or more URI roots to limit the search to
@ -167,10 +173,15 @@ class LibraryController(object):
:rtype: list of :class:`mopidy.models.SearchResult`
"""
query = _normalize_query(query or kwargs)
futures = [
backend.library.find_exact(query=query, uris=backend_uris)
for (backend, backend_uris)
in self._get_backends_to_uris(uris).items()]
futures = []
for backend, backend_uris in self._get_backends_to_uris(uris).items():
if hasattr(backend.library, 'find_exact'):
futures.append(backend.library.find_exact(
query=query, uris=backend_uris))
else:
futures.append(backend.library.search(
query=query, uris=backend_uris, exact=True))
return [result for result in pykka.get_all(futures) if result]
def lookup(self, uri=None, uris=None):

View File

@ -212,54 +212,50 @@ class CoreLibraryTest(unittest.TestCase):
result1 = SearchResult(tracks=[track1])
result2 = SearchResult(tracks=[track2])
self.library1.find_exact().get.return_value = result1
self.library1.find_exact.reset_mock()
self.library2.find_exact().get.return_value = result2
self.library2.find_exact.reset_mock()
self.library1.search.return_value.get.return_value = result1
self.library2.search.return_value.get.return_value = result2
result = self.core.library.find_exact(any=['a'])
self.assertIn(result1, result)
self.assertIn(result2, result)
self.library1.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library2.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library1.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
self.library2.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
def test_find_exact_with_uris_selects_dummy1_backend(self):
self.core.library.find_exact(
any=['a'], uris=['dummy1:', 'dummy1:foo', 'dummy3:'])
self.library1.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=['dummy1:', 'dummy1:foo'])
self.assertFalse(self.library2.find_exact.called)
self.library1.search.assert_called_once_with(
query=dict(any=['a']), uris=['dummy1:', 'dummy1:foo'], exact=True)
self.assertFalse(self.library2.search.called)
def test_find_exact_with_uris_selects_both_backends(self):
self.core.library.find_exact(
any=['a'], uris=['dummy1:', 'dummy1:foo', 'dummy2:'])
self.library1.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=['dummy1:', 'dummy1:foo'])
self.library2.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=['dummy2:'])
self.library1.search.assert_called_once_with(
query=dict(any=['a']), uris=['dummy1:', 'dummy1:foo'], exact=True)
self.library2.search.assert_called_once_with(
query=dict(any=['a']), uris=['dummy2:'], exact=True)
def test_find_exact_filters_out_none(self):
track1 = Track(uri='dummy1:a')
result1 = SearchResult(tracks=[track1])
self.library1.find_exact().get.return_value = result1
self.library1.find_exact.reset_mock()
self.library2.find_exact().get.return_value = None
self.library2.find_exact.reset_mock()
self.library1.search.return_value.get.return_value = result1
self.library2.search.return_value.get.return_value = None
result = self.core.library.find_exact(any=['a'])
self.assertIn(result1, result)
self.assertNotIn(None, result)
self.library1.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library2.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library1.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
self.library2.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
def test_find_accepts_query_dict_instead_of_kwargs(self):
track1 = Track(uri='dummy1:a')
@ -267,19 +263,17 @@ class CoreLibraryTest(unittest.TestCase):
result1 = SearchResult(tracks=[track1])
result2 = SearchResult(tracks=[track2])
self.library1.find_exact().get.return_value = result1
self.library1.find_exact.reset_mock()
self.library2.find_exact().get.return_value = result2
self.library2.find_exact.reset_mock()
self.library1.search.return_value.get.return_value = result1
self.library2.search.return_value.get.return_value = result2
result = self.core.library.find_exact(dict(any=['a']))
self.assertIn(result1, result)
self.assertIn(result2, result)
self.library1.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library2.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
self.library1.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
self.library2.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
def test_search_combines_results_from_all_backends(self):
track1 = Track(uri='dummy1:a')
@ -363,5 +357,29 @@ class CoreLibraryTest(unittest.TestCase):
def test_find_exact_normalises_bad_queries(self):
self.core.library.find_exact({'any': 'foobar'})
self.library1.find_exact.assert_called_once_with(
query={'any': ['foobar']}, uris=None)
self.library1.search.assert_called_once_with(
query={'any': ['foobar']}, uris=None, exact=True)
class LegacyLibraryProvider(backend.LibraryProvider):
def find_exact(self, query=None, uris=None):
pass
class LegacyCoreLibraryTest(unittest.TestCase):
def test_backend_with_find_exact_still_works(self):
b1 = mock.Mock()
b1.uri_schemes.get.return_value = ['dummy1']
b1.library = mock.Mock(spec=LegacyLibraryProvider)
b2 = mock.Mock()
b2.uri_schemes.get.return_value = ['dummy2']
b2.library = mock.Mock(spec=backend.LibraryProvider)
c = core.Core(mixer=None, backends=[b1, b2])
c.library.find_exact(query={'any': ['a']})
b1.library.find_exact.assert_called_once_with(
query=dict(any=['a']), uris=None)
b2.library.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)