Merge branch 'develop' into feature/core-dont-trust-backends
Note that this merge also updated core.playlists.create to combine the 1.0.5 fix with these changes. Conflicts: mopidy/core/playlists.py
This commit is contained in:
commit
cfd4dcb8dd
@ -53,6 +53,15 @@ Internal changes
|
||||
:issue:`1115`)
|
||||
|
||||
|
||||
v1.0.5 (UNRELEASED)
|
||||
===================
|
||||
|
||||
Bug fix release.
|
||||
|
||||
- Core: Add workaround for playlist providers that do not support
|
||||
creating playlists. (Fixes: :issue:`1162`, PR :issue:`1165`)
|
||||
|
||||
|
||||
v1.0.4 (2015-04-30)
|
||||
===================
|
||||
|
||||
|
||||
@ -148,20 +148,18 @@ class PlaylistsController(object):
|
||||
:rtype: :class:`mopidy.models.Playlist` or :class:`None`
|
||||
"""
|
||||
if uri_scheme in self.backends.with_playlists:
|
||||
backend = self.backends.with_playlists[uri_scheme]
|
||||
backends = [self.backends.with_playlists[uri_scheme]]
|
||||
else:
|
||||
# TODO: loop over backends until one of them doesn't return None
|
||||
backend = list(self.backends.with_playlists.values())[0]
|
||||
backends = self.backends.with_playlists.values()
|
||||
|
||||
with _backend_error_handling(backend):
|
||||
playlist = backend.playlists.create(name).get()
|
||||
|
||||
if playlist is None:
|
||||
return None
|
||||
|
||||
validation.check_instance(playlist, Playlist)
|
||||
listener.CoreListener.send('playlist_changed', playlist=playlist)
|
||||
return playlist
|
||||
for backend in backends:
|
||||
with _backend_error_handling(backend):
|
||||
result = backend.playlists.create(name).get()
|
||||
if result is None:
|
||||
continue
|
||||
validation.check_instance(result, Playlist)
|
||||
listener.CoreListener.send('playlist_changed', playlist=result)
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@ -45,15 +45,12 @@ class BackendEventsTest(unittest.TestCase):
|
||||
self.assertEqual(send.call_args[1]['mute'], True)
|
||||
|
||||
def test_tracklist_add_sends_tracklist_changed_event(self, send):
|
||||
send.reset_mock()
|
||||
|
||||
self.core.tracklist.add(uris=['dummy:a']).get()
|
||||
|
||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||
|
||||
def test_tracklist_clear_sends_tracklist_changed_event(self, send):
|
||||
self.core.tracklist.add(uris=['dummy:a']).get()
|
||||
send.reset_mock()
|
||||
|
||||
self.core.tracklist.clear().get()
|
||||
|
||||
@ -61,7 +58,6 @@ class BackendEventsTest(unittest.TestCase):
|
||||
|
||||
def test_tracklist_move_sends_tracklist_changed_event(self, send):
|
||||
self.core.tracklist.add(uris=['dummy:a', 'dummy:b']).get()
|
||||
send.reset_mock()
|
||||
|
||||
self.core.tracklist.move(0, 1, 1).get()
|
||||
|
||||
@ -69,7 +65,6 @@ class BackendEventsTest(unittest.TestCase):
|
||||
|
||||
def test_tracklist_remove_sends_tracklist_changed_event(self, send):
|
||||
self.core.tracklist.add(uris=['dummy:a']).get()
|
||||
send.reset_mock()
|
||||
|
||||
self.core.tracklist.remove({'uri': ['dummy:a']}).get()
|
||||
|
||||
@ -77,29 +72,22 @@ class BackendEventsTest(unittest.TestCase):
|
||||
|
||||
def test_tracklist_shuffle_sends_tracklist_changed_event(self, send):
|
||||
self.core.tracklist.add(uris=['dummy:a', 'dummy:b']).get()
|
||||
send.reset_mock()
|
||||
|
||||
self.core.tracklist.shuffle().get()
|
||||
|
||||
self.assertEqual(send.call_args[0][0], 'tracklist_changed')
|
||||
|
||||
def test_playlists_refresh_sends_playlists_loaded_event(self, send):
|
||||
send.reset_mock()
|
||||
|
||||
self.core.playlists.refresh().get()
|
||||
|
||||
self.assertEqual(send.call_args[0][0], 'playlists_loaded')
|
||||
|
||||
def test_playlists_refresh_uri_sends_playlists_loaded_event(self, send):
|
||||
send.reset_mock()
|
||||
|
||||
self.core.playlists.refresh(uri_scheme='dummy').get()
|
||||
|
||||
self.assertEqual(send.call_args[0][0], 'playlists_loaded')
|
||||
|
||||
def test_playlists_create_sends_playlist_changed_event(self, send):
|
||||
send.reset_mock()
|
||||
|
||||
self.core.playlists.create('foo').get()
|
||||
|
||||
self.assertEqual(send.call_args[0][0], 'playlist_changed')
|
||||
@ -112,7 +100,6 @@ class BackendEventsTest(unittest.TestCase):
|
||||
def test_playlists_save_sends_playlist_changed_event(self, send):
|
||||
playlist = self.core.playlists.create('foo').get()
|
||||
playlist = playlist.replace(name='bar')
|
||||
send.reset_mock()
|
||||
|
||||
self.core.playlists.save(playlist).get()
|
||||
|
||||
|
||||
@ -17,8 +17,7 @@ class BaseCoreLibraryTest(unittest.TestCase):
|
||||
self.backend1.uri_schemes.get.return_value = ['dummy1']
|
||||
self.backend1.actor_ref.actor_class.__name__ = 'DummyBackend1'
|
||||
self.library1 = mock.Mock(spec=backend.LibraryProvider)
|
||||
self.library1.get_images().get.return_value = {}
|
||||
self.library1.get_images.reset_mock()
|
||||
self.library1.get_images.return_value.get.return_value = {}
|
||||
self.library1.root_directory.get.return_value = dummy1_root
|
||||
self.backend1.library = self.library1
|
||||
|
||||
@ -27,8 +26,7 @@ class BaseCoreLibraryTest(unittest.TestCase):
|
||||
self.backend2.uri_schemes.get.return_value = ['dummy2', 'du2']
|
||||
self.backend2.actor_ref.actor_class.__name__ = 'DummyBackend2'
|
||||
self.library2 = mock.Mock(spec=backend.LibraryProvider)
|
||||
self.library2.get_images().get.return_value = {}
|
||||
self.library2.get_images.reset_mock()
|
||||
self.library2.get_images.return_value.get.return_value = {}
|
||||
self.library2.root_directory.get.return_value = dummy2_root
|
||||
self.backend2.library = self.library2
|
||||
|
||||
@ -68,20 +66,17 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
self.library2.get_images.assert_called_once_with(['dummy2:track'])
|
||||
|
||||
def test_get_images_returns_images(self):
|
||||
self.library1.get_images().get.return_value = {
|
||||
self.library1.get_images.return_value.get.return_value = {
|
||||
'dummy1:track': [Image(uri='uri')]}
|
||||
self.library1.get_images.reset_mock()
|
||||
|
||||
result = self.core.library.get_images(['dummy1:track'])
|
||||
self.assertEqual({'dummy1:track': (Image(uri='uri'),)}, result)
|
||||
|
||||
def test_get_images_merges_results(self):
|
||||
self.library1.get_images().get.return_value = {
|
||||
self.library1.get_images.return_value.get.return_value = {
|
||||
'dummy1:track': [Image(uri='uri1')]}
|
||||
self.library1.get_images.reset_mock()
|
||||
self.library2.get_images().get.return_value = {
|
||||
self.library2.get_images.return_value.get.return_value = {
|
||||
'dummy2:track': [Image(uri='uri2')]}
|
||||
self.library2.get_images.reset_mock()
|
||||
|
||||
result = self.core.library.get_images(
|
||||
['dummy1:track', 'dummy2:track', 'dummy3:track', 'dummy4:track'])
|
||||
@ -109,11 +104,10 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
self.assertFalse(self.library2.browse.called)
|
||||
|
||||
def test_browse_dummy1_selects_dummy1_backend(self):
|
||||
self.library1.browse().get.return_value = [
|
||||
self.library1.browse.return_value.get.return_value = [
|
||||
Ref.directory(uri='dummy1:directory:/foo/bar', name='bar'),
|
||||
Ref.track(uri='dummy1:track:/foo/baz.mp3', name='Baz'),
|
||||
]
|
||||
self.library1.browse.reset_mock()
|
||||
|
||||
self.core.library.browse('dummy1:directory:/foo')
|
||||
|
||||
@ -122,11 +116,10 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
self.library1.browse.assert_called_with('dummy1:directory:/foo')
|
||||
|
||||
def test_browse_dummy2_selects_dummy2_backend(self):
|
||||
self.library2.browse().get.return_value = [
|
||||
self.library2.browse.return_value.get.return_value = [
|
||||
Ref.directory(uri='dummy2:directory:/bar/baz', name='quux'),
|
||||
Ref.track(uri='dummy2:track:/bar/foo.mp3', name='Baz'),
|
||||
]
|
||||
self.library2.browse.reset_mock()
|
||||
|
||||
self.core.library.browse('dummy2:directory:/bar')
|
||||
|
||||
@ -142,11 +135,10 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
self.assertEqual(self.library2.browse.call_count, 0)
|
||||
|
||||
def test_browse_dir_returns_subdirs_and_tracks(self):
|
||||
self.library1.browse().get.return_value = [
|
||||
self.library1.browse.return_value.get.return_value = [
|
||||
Ref.directory(uri='dummy1:directory:/foo/bar', name='Bar'),
|
||||
Ref.track(uri='dummy1:track:/foo/baz.mp3', name='Baz'),
|
||||
]
|
||||
self.library1.browse.reset_mock()
|
||||
|
||||
result = self.core.library.browse('dummy1:directory:/foo')
|
||||
self.assertEqual(result, [
|
||||
@ -205,10 +197,8 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
result1 = SearchResult(tracks=[track1])
|
||||
result2 = SearchResult(tracks=[track2])
|
||||
|
||||
self.library1.search().get.return_value = result1
|
||||
self.library1.search.reset_mock()
|
||||
self.library2.search().get.return_value = result2
|
||||
self.library2.search.reset_mock()
|
||||
self.library1.search.return_value.get.return_value = result1
|
||||
self.library2.search.return_value.get.return_value = result2
|
||||
|
||||
result = self.core.library.search({'any': ['a']})
|
||||
|
||||
@ -240,10 +230,8 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
track1 = Track(uri='dummy1:a')
|
||||
result1 = SearchResult(tracks=[track1])
|
||||
|
||||
self.library1.search().get.return_value = result1
|
||||
self.library1.search.reset_mock()
|
||||
self.library2.search().get.return_value = None
|
||||
self.library2.search.reset_mock()
|
||||
self.library1.search.return_value.get.return_value = result1
|
||||
self.library2.search.return_value.get.return_value = None
|
||||
|
||||
result = self.core.library.search({'any': ['a']})
|
||||
|
||||
@ -260,10 +248,8 @@ class CoreLibraryTest(BaseCoreLibraryTest):
|
||||
result1 = SearchResult(tracks=[track1])
|
||||
result2 = SearchResult(tracks=[track2])
|
||||
|
||||
self.library1.search().get.return_value = result1
|
||||
self.library1.search.reset_mock()
|
||||
self.library2.search().get.return_value = result2
|
||||
self.library2.search.reset_mock()
|
||||
self.library1.search.return_value.get.return_value = result1
|
||||
self.library2.search.return_value.get.return_value = result2
|
||||
|
||||
result = self.core.library.search({'any': ['a']})
|
||||
|
||||
|
||||
@ -21,15 +21,13 @@ class CorePlaybackTest(unittest.TestCase):
|
||||
self.backend1 = mock.Mock()
|
||||
self.backend1.uri_schemes.get.return_value = ['dummy1']
|
||||
self.playback1 = mock.Mock(spec=backend.PlaybackProvider)
|
||||
self.playback1.get_time_position().get.return_value = 1000
|
||||
self.playback1.reset_mock()
|
||||
self.playback1.get_time_position.return_value.get.return_value = 1000
|
||||
self.backend1.playback = self.playback1
|
||||
|
||||
self.backend2 = mock.Mock()
|
||||
self.backend2.uri_schemes.get.return_value = ['dummy2']
|
||||
self.playback2 = mock.Mock(spec=backend.PlaybackProvider)
|
||||
self.playback2.get_time_position().get.return_value = 2000
|
||||
self.playback2.reset_mock()
|
||||
self.playback2.get_time_position.return_value.get.return_value = 2000
|
||||
self.backend2.playback = self.playback2
|
||||
|
||||
# A backend without the optional playback provider
|
||||
|
||||
@ -90,8 +90,7 @@ class PlaylistTest(BasePlaylistsTest):
|
||||
|
||||
def test_create_without_uri_scheme_uses_first_backend(self):
|
||||
playlist = Playlist()
|
||||
self.sp1.create().get.return_value = playlist
|
||||
self.sp1.reset_mock()
|
||||
self.sp1.create.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.create('foo')
|
||||
|
||||
@ -99,10 +98,31 @@ class PlaylistTest(BasePlaylistsTest):
|
||||
self.sp1.create.assert_called_once_with('foo')
|
||||
self.assertFalse(self.sp2.create.called)
|
||||
|
||||
def test_create_without_uri_scheme_ignores_none_result(self):
|
||||
playlist = Playlist()
|
||||
self.sp1.create.return_value.get.return_value = None
|
||||
self.sp2.create.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.create('foo')
|
||||
|
||||
self.assertEqual(playlist, result)
|
||||
self.sp1.create.assert_called_once_with('foo')
|
||||
self.sp2.create.assert_called_once_with('foo')
|
||||
|
||||
def test_create_without_uri_scheme_ignores_exception(self):
|
||||
playlist = Playlist()
|
||||
self.sp1.create.return_value.get.side_effect = Exception
|
||||
self.sp2.create.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.create('foo')
|
||||
|
||||
self.assertEqual(playlist, result)
|
||||
self.sp1.create.assert_called_once_with('foo')
|
||||
self.sp2.create.assert_called_once_with('foo')
|
||||
|
||||
def test_create_with_uri_scheme_selects_the_matching_backend(self):
|
||||
playlist = Playlist()
|
||||
self.sp2.create().get.return_value = playlist
|
||||
self.sp2.reset_mock()
|
||||
self.sp2.create.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.create('foo', uri_scheme='dummy2')
|
||||
|
||||
@ -112,8 +132,7 @@ class PlaylistTest(BasePlaylistsTest):
|
||||
|
||||
def test_create_with_unsupported_uri_scheme_uses_first_backend(self):
|
||||
playlist = Playlist()
|
||||
self.sp1.create().get.return_value = playlist
|
||||
self.sp1.reset_mock()
|
||||
self.sp1.create.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.create('foo', uri_scheme='dummy3')
|
||||
|
||||
@ -190,8 +209,7 @@ class PlaylistTest(BasePlaylistsTest):
|
||||
|
||||
def test_save_selects_the_dummy1_backend(self):
|
||||
playlist = Playlist(uri='dummy1:a')
|
||||
self.sp1.save().get.return_value = playlist
|
||||
self.sp1.reset_mock()
|
||||
self.sp1.save.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.save(playlist)
|
||||
|
||||
@ -201,8 +219,7 @@ class PlaylistTest(BasePlaylistsTest):
|
||||
|
||||
def test_save_selects_the_dummy2_backend(self):
|
||||
playlist = Playlist(uri='dummy2:a')
|
||||
self.sp2.save().get.return_value = playlist
|
||||
self.sp2.reset_mock()
|
||||
self.sp2.save.return_value.get.return_value = playlist
|
||||
|
||||
result = self.core.playlists.save(playlist)
|
||||
|
||||
|
||||
@ -12,8 +12,6 @@ from mopidy.http import actor
|
||||
class HttpEventsTest(unittest.TestCase):
|
||||
|
||||
def test_track_playback_paused_is_broadcasted(self, broadcast):
|
||||
broadcast.reset_mock()
|
||||
|
||||
actor.on_event('track_playback_paused', foo='bar')
|
||||
|
||||
self.assertDictEqual(
|
||||
@ -23,8 +21,6 @@ class HttpEventsTest(unittest.TestCase):
|
||||
})
|
||||
|
||||
def test_track_playback_resumed_is_broadcasted(self, broadcast):
|
||||
broadcast.reset_mock()
|
||||
|
||||
actor.on_event('track_playback_resumed', foo='bar')
|
||||
|
||||
self.assertDictEqual(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user