core/backend: Stop supporting old search signatures

All backends are expected to support the exact argument. A friendly log message
will be printed to prompt users to upgrade backends that fail due to this.
This commit is contained in:
Thomas Adamcik 2015-03-24 23:54:49 +01:00
parent a8e6cd26dc
commit ead725e995
4 changed files with 45 additions and 62 deletions

View File

@ -242,25 +242,21 @@ class LibraryController(object):
The ``exact`` keyword argument, which replaces :meth:`find_exact`.
"""
query = _normalize_query(query or kwargs)
futures = []
futures = {}
for backend, backend_uris in self._get_backends_to_uris(uris).items():
if hasattr(backend.library, 'find_exact'):
# Backends with find_exact probably don't have support for
# search with the exact kwarg, so give them the legacy calls.
if exact:
futures.append(backend.library.find_exact(
query=query, uris=backend_uris))
else:
futures.append(backend.library.search(
query=query, uris=backend_uris))
else:
# Assume backends without find_exact are up to date. Worst case
# the exact gets swallowed by the **kwargs and things hopefully
# still work.
futures.append(backend.library.search(
query=query, uris=backend_uris, exact=exact))
futures[backend] = backend.library.search(
query=query, uris=backend_uris, exact=exact)
return [result for result in pykka.get_all(futures) if result]
results = []
for backend, future in futures.items():
try:
results.append(future.get())
except TypeError:
backend_name = backend.actor_ref.actor_class.__name__
logger.warning(
'%s does not implement library.search() with exact '
'support. Please upgrade it.', backend_name)
return [r for r in results if r]
def _normalize_query(query):

View File

@ -51,12 +51,7 @@ class LocalLibraryProvider(backend.LibraryProvider):
tracks = [tracks]
return tracks
def find_exact(self, query=None, uris=None):
def search(self, query=None, uris=None, exact=False):
if not self._library:
return None
return self._library.search(query=query, uris=uris, exact=True)
def search(self, query=None, uris=None):
if not self._library:
return None
return self._library.search(query=query, uris=uris, exact=False)
return self._library.search(query=query, uris=uris, exact=exact)

View File

@ -361,42 +361,35 @@ class CoreLibraryTest(unittest.TestCase):
query={'any': ['foobar']}, uris=None, exact=True)
class LegacyLibraryProvider(backend.LibraryProvider):
def find_exact(self, query=None, uris=None):
pass
class LegacyFindExactToSearchLibraryTest(unittest.TestCase):
def setUp(self): # noqa: N802
self.backend = mock.Mock()
self.backend.actor_ref.actor_class.__name__ = 'DummyBackend'
self.backend.uri_schemes.get.return_value = ['dummy']
self.backend.library = mock.Mock(spec=backend.LibraryProvider)
self.core = core.Core(mixer=None, backends=[self.backend])
class LegacyCoreLibraryTest(unittest.TestCase):
def test_backend_with_find_exact_gets_find_exact_call(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(
def test_core_find_exact_calls_backend_search_with_exact(self):
self.core.library.find_exact(query={'any': ['a']})
self.backend.library.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
def test_backend_with_find_exact_gets_search_without_exact_arg(self):
b1 = mock.Mock()
b1.uri_schemes.get.return_value = ['dummy1']
b1.library = mock.Mock(spec=LegacyLibraryProvider)
def test_core_find_exact_handles_legacy_backend(self):
self.backend.library.search.return_value.get.side_effect = TypeError
self.core.library.find_exact(query={'any': ['a']})
# We are just testing that this doesn't fail.
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.search(query={'any': ['a']})
b1.library.search.assert_called_once_with(
query=dict(any=['a']), uris=None)
b2.library.search.assert_called_once_with(
def test_core_search_call_backend_search_with_exact(self):
self.core.library.search(query={'any': ['a']})
self.backend.library.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=False)
def test_core_search_with_exact_call_backend_search_with_exact(self):
self.core.library.search(query={'any': ['a']}, exact=True)
self.backend.library.search.assert_called_once_with(
query=dict(any=['a']), uris=None, exact=True)
def test_core_search_with_handles_legacy_backend(self):
self.backend.library.search.return_value.get.side_effect = TypeError
self.core.library.search(query={'any': ['a']}, exact=True)
# We are just testing that this doesn't fail.

View File

@ -46,16 +46,15 @@ class DummyLibraryProvider(backend.LibraryProvider):
def get_distinct(self, field, query=None):
return self.dummy_get_distinct_result.get(field, set())
def find_exact(self, **query):
return self.dummy_find_exact_result
def lookup(self, uri):
return [t for t in self.dummy_library if uri == t.uri]
def refresh(self, uri=None):
pass
def search(self, **query):
def search(self, query=None, uris=None, exact=False):
if exact: # TODO: remove uses of dummy_find_exact_result
return self.dummy_find_exact_result
return self.dummy_search_result