From d24a81425cb8005ac0c6dd31ad70f3ec7151e4bf Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 20:02:08 +0200 Subject: [PATCH 01/34] Convert uri handler to file:// --- mopidy/backends/gstreamer.py | 2 +- tests/backends/gstreamer_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/backends/gstreamer.py b/mopidy/backends/gstreamer.py index 8a79ff11..4e5b83f7 100644 --- a/mopidy/backends/gstreamer.py +++ b/mopidy/backends/gstreamer.py @@ -41,7 +41,7 @@ class GStreamerBackend(BaseBackend): self.playback = GStreamerPlaybackController(self) self.stored_playlists = GStreamerStoredPlaylistsController(self) self.current_playlist = BaseCurrentPlaylistController(self) - self.uri_handlers = [u'file:'] + self.uri_handlers = [u'file://'] class GStreamerPlaybackController(BasePlaybackController): diff --git a/tests/backends/gstreamer_test.py b/tests/backends/gstreamer_test.py index 71e92a53..2407b7de 100644 --- a/tests/backends/gstreamer_test.py +++ b/tests/backends/gstreamer_test.py @@ -33,7 +33,7 @@ class GStreamerPlaybackControllerTest(BasePlaybackControllerTest, unittest.TestC self.backend.current_playlist.add(track) def test_uri_handler(self): - self.assert_('file:' in self.backend.uri_handlers) + self.assert_('file://' in self.backend.uri_handlers) def test_play_mp3(self): self.add_track('blank.mp3') From c93d8470ce12d64f57979220d7df832028b675ec Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 20:03:00 +0200 Subject: [PATCH 02/34] Substitute file: with file:// all over --- mopidy/backends/gstreamer.py | 4 ++-- mopidy/utils.py | 4 ++-- tests/backends/gstreamer_test.py | 8 ++++---- tests/utils_test.py | 15 ++++++--------- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/mopidy/backends/gstreamer.py b/mopidy/backends/gstreamer.py index 4e5b83f7..4be2088b 100644 --- a/mopidy/backends/gstreamer.py +++ b/mopidy/backends/gstreamer.py @@ -170,8 +170,8 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController): with open(file_path, 'w') as file: for track in playlist.tracks: - if track.uri.startswith('file:'): - file.write(track.uri[len('file:'):] + '\n') + if track.uri.startswith('file://'): + file.write(track.uri[len('file://'):] + '\n') else: file.write(track.uri + '\n') diff --git a/mopidy/utils.py b/mopidy/utils.py index f0d972ee..eee0cac0 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -124,11 +124,11 @@ def m3u_to_uris(file_path): if line.startswith('#'): continue - if line.startswith('file:'): + if line.startswith('file://'): uris.append(line) else: file = os.path.join(folder, line) path = urllib.pathname2url(file.encode('utf-8')) - uris.append('file:' + path) + uris.append('file://' + path) return uris diff --git a/tests/backends/gstreamer_test.py b/tests/backends/gstreamer_test.py index 2407b7de..6d010b9b 100644 --- a/tests/backends/gstreamer_test.py +++ b/tests/backends/gstreamer_test.py @@ -14,7 +14,7 @@ folder = os.path.dirname(__file__) folder = os.path.join(folder, '..', 'data') folder = os.path.abspath(folder) song = os.path.join(folder, 'song%s.wav') -generate_song = lambda i: 'file:' + urllib.pathname2url(song % i) +generate_song = lambda i: 'file://' + urllib.pathname2url(song % i) # FIXME can be switched to generic test class GStreamerCurrentPlaylistHandlerTest(BaseCurrentPlaylistControllerTest, unittest.TestCase): @@ -28,7 +28,7 @@ class GStreamerPlaybackControllerTest(BasePlaybackControllerTest, unittest.TestC backend_class = GStreamerBackend def add_track(self, file): - uri = 'file:' + urllib.pathname2url(os.path.join(folder, file)) + uri = 'file://' + urllib.pathname2url(os.path.join(folder, file)) track = Track(uri=uri, id=1, length=4464) self.backend.current_playlist.add(track) @@ -82,7 +82,7 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle def test_playlist_contents_get_written_to_disk(self): track = Track(uri=generate_song(1)) - uri = track.uri[len('file:'):] + uri = track.uri[len('file://'):] playlist = Playlist(tracks=[track], name='test') file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u') @@ -95,7 +95,7 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle def test_playlists_are_loaded_at_startup(self): track = Track(uri=generate_song(1)) - uri = track.uri[len('file:'):] + uri = track.uri[len('file://'):] playlist = Playlist(tracks=[track], name='test') file_path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u') diff --git a/tests/utils_test.py b/tests/utils_test.py index 4531745d..05b5f244 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -17,9 +17,9 @@ def data(name): song1_path = data('song1.mp3') song2_path = data('song2.mp3') encoded_path = data(u'æøå.mp3') -song1_uri = 'file:' + urllib.pathname2url(song1_path) -song2_uri = 'file:' + urllib.pathname2url(song2_path) -encoded_uri = 'file:' + urllib.pathname2url(encoded_path.encode('utf-8')) +song1_uri = 'file://' + urllib.pathname2url(song1_path) +song2_uri = 'file://' + urllib.pathname2url(song2_path) +encoded_uri = 'file://' + urllib.pathname2url(encoded_path.encode('utf-8')) class M3UToUriTest(unittest.TestCase): @@ -39,9 +39,8 @@ class M3UToUriTest(unittest.TestCase): with tempfile.NamedTemporaryFile() as file: file.write(song1_path) file.flush() - uris = m3u_to_uris(file.name) - self.assertEqual([song1_uri], uris) + self.assertEqual([song1_uri], uris) def test_file_with_multiple_absolute_files(self): with tempfile.NamedTemporaryFile() as file: @@ -49,17 +48,15 @@ class M3UToUriTest(unittest.TestCase): file.write('# comment \n') file.write(song2_path) file.flush() - uris = m3u_to_uris(file.name) - self.assertEqual([song1_uri, song2_uri], uris) + self.assertEqual([song1_uri, song2_uri], uris) def test_file_with_uri(self): with tempfile.NamedTemporaryFile() as file: file.write(song1_uri) file.flush() - uris = m3u_to_uris(file.name) - self.assertEqual([song1_uri], uris) + self.assertEqual([song1_uri], uris) def test_encoding_is_latin1(self): uris = m3u_to_uris(data('encoding.m3u')) From 19fe5d35062982f322799416b11353c4c361cd97 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 20:51:48 +0200 Subject: [PATCH 03/34] Add FIXME --- mopidy/backends/gstreamer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mopidy/backends/gstreamer.py b/mopidy/backends/gstreamer.py index 4be2088b..dbbb3ee2 100644 --- a/mopidy/backends/gstreamer.py +++ b/mopidy/backends/gstreamer.py @@ -132,6 +132,7 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController): playlist = Playlist(tracks=tracks, name=name) # FIXME playlist name needs better handling + # FIXME tracks should come from lib. lookup playlists.append(playlist) From d64980411d8e524bb6c4b1781c4b633bd225f064 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 21:25:23 +0200 Subject: [PATCH 04/34] Rename m3u conversion helper to parse_m3u --- mopidy/backends/gstreamer.py | 4 ++-- mopidy/utils.py | 2 +- tests/utils_test.py | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mopidy/backends/gstreamer.py b/mopidy/backends/gstreamer.py index dbbb3ee2..8af42a77 100644 --- a/mopidy/backends/gstreamer.py +++ b/mopidy/backends/gstreamer.py @@ -16,7 +16,7 @@ import threading from mopidy.backends import * from mopidy.models import Playlist, Track from mopidy import settings -from mopidy.utils import m3u_to_uris +from mopidy.utils import parse_m3u logger = logging.getLogger(u'backends.gstreamer') @@ -127,7 +127,7 @@ class GStreamerStoredPlaylistsController(BaseStoredPlaylistsController): for m3u in glob.glob(os.path.join(self._folder, '*.m3u')): name = os.path.basename(m3u)[:len('.m3u')] - track_uris = m3u_to_uris(m3u) + track_uris = parse_m3u(m3u) tracks = map(lambda u: Track(uri=u), track_uris) playlist = Playlist(tracks=tracks, name=name) diff --git a/mopidy/utils.py b/mopidy/utils.py index eee0cac0..8edbc20d 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -93,7 +93,7 @@ def spotify_uri_to_int(uri, output_bits=31): full_id >>= output_bits return int(compressed_id) -def m3u_to_uris(file_path): +def parse_m3u(file_path): """ Convert M3U file list of uris diff --git a/tests/utils_test.py b/tests/utils_test.py index 05b5f244..0cc8f1f4 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -5,7 +5,7 @@ import tempfile import unittest import urllib -from mopidy.utils import m3u_to_uris +from mopidy.utils import parse_m3u def data(name): folder = os.path.dirname(__file__) @@ -24,22 +24,22 @@ encoded_uri = 'file://' + urllib.pathname2url(encoded_path.encode('utf-8')) class M3UToUriTest(unittest.TestCase): def test_empty_file(self): - uris = m3u_to_uris(data('empty.m3u')) + uris = parse_m3u(data('empty.m3u')) self.assertEqual([], uris) def test_basic_file(self): - uris = m3u_to_uris(data('one.m3u')) + uris = parse_m3u(data('one.m3u')) self.assertEqual([song1_uri], uris) def test_file_with_comment(self): - uris = m3u_to_uris(data('comment.m3u')) + uris = parse_m3u(data('comment.m3u')) self.assertEqual([song1_uri], uris) def test_file_with_absolute_files(self): with tempfile.NamedTemporaryFile() as file: file.write(song1_path) file.flush() - uris = m3u_to_uris(file.name) + uris = parse_m3u(file.name) self.assertEqual([song1_uri], uris) def test_file_with_multiple_absolute_files(self): @@ -48,16 +48,16 @@ class M3UToUriTest(unittest.TestCase): file.write('# comment \n') file.write(song2_path) file.flush() - uris = m3u_to_uris(file.name) + uris = parse_m3u(file.name) self.assertEqual([song1_uri, song2_uri], uris) def test_file_with_uri(self): with tempfile.NamedTemporaryFile() as file: file.write(song1_uri) file.flush() - uris = m3u_to_uris(file.name) + uris = parse_m3u(file.name) self.assertEqual([song1_uri], uris) def test_encoding_is_latin1(self): - uris = m3u_to_uris(data('encoding.m3u')) + uris = parse_m3u(data('encoding.m3u')) self.assertEqual([encoded_uri], uris) From 06d6fd81c725cf2af4831a11dda49d45bfc24e81 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 22:47:35 +0200 Subject: [PATCH 05/34] Add __eq__ to Artist --- mopidy/models.py | 6 ++++++ tests/models_test.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/mopidy/models.py b/mopidy/models.py index 6d0b0dee..6844b254 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -32,6 +32,12 @@ class Artist(ImmutableObject): #: The artist name. Read-only. name = None + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + class Album(ImmutableObject): """ diff --git a/tests/models_test.py b/tests/models_test.py index 43d6ca53..3c1794dd 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -16,6 +16,36 @@ class ArtistTest(unittest.TestCase): self.assertEqual(artist.name, name) self.assertRaises(AttributeError, setattr, artist, 'name', None) + def test_eq_name(self): + artist1 = Artist(name=u'name') + artist2 = Artist(name=u'name') + self.assertEqual(artist1, artist2) + + def test_eq_uri(self): + artist1 = Artist(uri=u'uri') + artist2 = Artist(uri=u'uri') + self.assertEqual(artist1, artist2) + + def test_eq(self): + artist1 = Artist(uri=u'uri', name=u'name') + artist2 = Artist(uri=u'uri', name=u'name') + self.assertEqual(artist1, artist2) + + def test_ne_name(self): + artist1 = Artist(name=u'name1') + artist2 = Artist(name=u'name2') + self.assertNotEqual(artist1, artist2) + + def test_ne_uri(self): + artist1 = Artist(uri=u'uri1') + artist2 = Artist(uri=u'uri2') + self.assertNotEqual(artist1, artist2) + + def test_ne(self): + artist1 = Artist(uri=u'uri1', name=u'name1') + artist2 = Artist(uri=u'uri2', name=u'name2') + self.assertNotEqual(artist1, artist2) + class AlbumTest(unittest.TestCase): def test_uri(self): From 3bc795ee95200660ee1fc1eb7fe04402ff56b50b Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 22:55:36 +0200 Subject: [PATCH 06/34] Add __eq__ to album --- mopidy/models.py | 6 +++++ tests/models_test.py | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/mopidy/models.py b/mopidy/models.py index 6844b254..21812f9f 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -64,6 +64,12 @@ class Album(ImmutableObject): self._artists = kwargs.pop('artists', []) super(Album, self).__init__(*args, **kwargs) + def __eq__(self, other): + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + @property def artists(self): """List of :class:`Artist` elements. Read-only.""" diff --git a/tests/models_test.py b/tests/models_test.py index 3c1794dd..3135e4f2 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -72,6 +72,58 @@ class AlbumTest(unittest.TestCase): self.assertEqual(album.num_tracks, num_tracks) self.assertRaises(AttributeError, setattr, album, 'num_tracks', None) + def test_eq_name(self): + album1 = Album(name=u'name') + album2 = Album(name=u'name') + self.assertEqual(album1, album2) + + def test_eq_uri(self): + album1 = Album(uri=u'uri') + album2 = Album(uri=u'uri') + self.assertEqual(album1, album2) + + def test_eq_artists(self): + artists = [Artist()] + album1 = Album(artists=artists) + album2 = Album(artists=artists) + self.assertEqual(album1, album2) + + def test_eq_num_tracks(self): + album1 = Album(num_tracks=2) + album2 = Album(num_tracks=2) + self.assertEqual(album1, album2) + + def test_eq(self): + artists = [Artist()] + album1 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2) + album2 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2) + self.assertEqual(album1, album2) + + def test_ne_name(self): + album1 = Album(name=u'name1') + album2 = Album(name=u'name2') + self.assertNotEqual(album1, album2) + + def test_ne_uri(self): + album1 = Album(uri=u'uri1') + album2 = Album(uri=u'uri2') + self.assertNotEqual(album1, album2) + + def test_ne_artists(self): + album1 = Album(artists=[Artist(name=u'name1')]) + album2 = Album(artists=[Artist(name=u'name2')]) + self.assertNotEqual(album1, album2) + + def test_ne_num_tracks(self): + album1 = Album(num_tracks=1) + album2 = Album(num_tracks=2) + self.assertNotEqual(album1, album2) + + def test_ne(self): + album1 = Album(name=u'name1', uri=u'uri1', artists=[Artist(name=u'name1')], num_tracks=1) + album2 = Album(name=u'name2', uri=u'uri2', artists=[Artist(name=u'name2')], num_tracks=2) + self.assertNotEqual(album1, album2) + class TrackTest(unittest.TestCase): def test_uri(self): From f8b2d523336e6522dd23ee4cda1b29ff22d23fad Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 23:12:24 +0200 Subject: [PATCH 07/34] Add __eq__ to Track --- mopidy/models.py | 9 ++++ tests/models_test.py | 113 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/mopidy/models.py b/mopidy/models.py index 21812f9f..d6b42b08 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -126,6 +126,15 @@ class Track(ImmutableObject): self._artists = kwargs.pop('artists', []) super(Track, self).__init__(*args, **kwargs) + def __eq__(self, other): + if other is None: + return False + + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + @property def artists(self): """List of :class:`Artist`. Read-only.""" diff --git a/tests/models_test.py b/tests/models_test.py index 3135e4f2..6dfde964 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -219,6 +219,119 @@ class TrackTest(unittest.TestCase): track = Track(artists=[Artist(name=u'ABBA'), Artist(name=u'Beatles')]) self.assertEqual(track.mpd_format_artists(), u'ABBA, Beatles') + def test_eq_uri(self): + track1 = Track(uri=u'uri1') + track2 = Track(uri=u'uri1') + self.assertEqual(track1, track2) + + def test_eq_name(self): + track1 = Track(name=u'name1') + track2 = Track(name=u'name1') + self.assertEqual(track1, track2) + + def test_eq_artists(self): + artists = [Artist()] + track1 = Track(artists=artists) + track2 = Track(artists=artists) + self.assertEqual(track1, track2) + + def test_eq_album(self): + album = Album() + track1 = Track(album=album) + track2 = Track(album=album) + self.assertEqual(track1, track2) + + def test_eq_track_no(self): + track1 = Track(track_no=1) + track2 = Track(track_no=1) + self.assertEqual(track1, track2) + + def test_eq_date(self): + date = dt.date.today() + track1 = Track(date=date) + track2 = Track(date=date) + self.assertEqual(track1, track2) + + def test_eq_length(self): + track1 = Track(length=100) + track2 = Track(length=100) + self.assertEqual(track1, track2) + + def test_eq_bitrate(self): + track1 = Track(bitrate=100) + track2 = Track(bitrate=100) + self.assertEqual(track1, track2) + + def test_eq_id(self): + track1 = Track(id=100) + track2 = Track(id=100) + self.assertEqual(track1, track2) + + def test_eq(self): + date = dt.date.today() + artists = [Artist()] + album = Album() + track1 = Track(uri=u'uri', name=u'name', artists=artists, album=album, + track_no=1, date=date, length=100, bitrate=100, id=2) + track2 = Track(uri=u'uri', name=u'name', artists=artists, album=album, + track_no=1, date=date, length=100, bitrate=100, id=2) + self.assertEqual(track1, track2) + + def test_ne_uri(self): + track1 = Track(uri=u'uri1') + track2 = Track(uri=u'uri2') + self.assertNotEqual(track1, track2) + + def test_ne_name(self): + track1 = Track(name=u'name1') + track2 = Track(name=u'name2') + self.assertNotEqual(track1, track2) + + def test_ne_artists(self): + track1 = Track(artists=[Artist(name=u'name1')]) + track2 = Track(artists=[Artist(name=u'name2')]) + self.assertNotEqual(track1, track2) + + def test_ne_album(self): + track1 = Track(album=Album(name=u'name1')) + track2 = Track(album=Album(name=u'name2')) + self.assertNotEqual(track1, track2) + + def test_ne_track_no(self): + track1 = Track(track_no=1) + track2 = Track(track_no=2) + self.assertNotEqual(track1, track2) + + def test_ne_date(self): + track1 = Track(date=dt.date.today()) + track2 = Track(date=dt.date.today()-dt.timedelta(days=1)) + self.assertNotEqual(track1, track2) + + def test_ne_length(self): + track1 = Track(length=100) + track2 = Track(length=200) + self.assertNotEqual(track1, track2) + + def test_ne_bitrate(self): + track1 = Track(bitrate=100) + track2 = Track(bitrate=200) + self.assertNotEqual(track1, track2) + + def test_ne_id(self): + track1 = Track(id=100) + track2 = Track(id=200) + self.assertNotEqual(track1, track2) + + def test_ne(self): + track1 = Track(uri=u'uri1', name=u'name1', + artists=[Artist(name=u'name1')], album=Album(name=u'name1'), + track_no=1, date=dt.date.today(), length=100, bitrate=100, id=2) + track2 = Track(uri=u'uri2', name=u'name2', + artists=[Artist(name=u'name2')], album=Album(name=u'name2'), + track_no=2, date=dt.date.today()-dt.timedelta(days=1), + length=200, bitrate=200, id=1) + self.assertNotEqual(track1, track2) + class PlaylistTest(unittest.TestCase): def test_uri(self): From b24d883db9ec72e6500217ddb7a5340de0c81598 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 23:15:33 +0200 Subject: [PATCH 08/34] Test comparing with None --- mopidy/models.py | 6 ++++++ tests/models_test.py | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/mopidy/models.py b/mopidy/models.py index d6b42b08..58077a31 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -33,6 +33,9 @@ class Artist(ImmutableObject): name = None def __eq__(self, other): + if other is None: + return False + return self.__dict__ == other.__dict__ def __ne__(self, other): @@ -65,6 +68,9 @@ class Album(ImmutableObject): super(Album, self).__init__(*args, **kwargs) def __eq__(self, other): + if other is None: + return False + return self.__dict__ == other.__dict__ def __ne__(self, other): diff --git a/tests/models_test.py b/tests/models_test.py index 6dfde964..eb7fa187 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -31,6 +31,9 @@ class ArtistTest(unittest.TestCase): artist2 = Artist(uri=u'uri', name=u'name') self.assertEqual(artist1, artist2) + def test_eq_none(self): + self.assertNotEqual(Artist(), None) + def test_ne_name(self): artist1 = Artist(name=u'name1') artist2 = Artist(name=u'name2') @@ -99,6 +102,9 @@ class AlbumTest(unittest.TestCase): album2 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2) self.assertEqual(album1, album2) + def test_eq_none(self): + self.assertNotEqual(Album(), None) + def test_ne_name(self): album1 = Album(name=u'name1') album2 = Album(name=u'name2') @@ -277,6 +283,9 @@ class TrackTest(unittest.TestCase): track_no=1, date=date, length=100, bitrate=100, id=2) self.assertEqual(track1, track2) + def test_eq_none(self): + self.assertNotEqual(Track(), None) + def test_ne_uri(self): track1 = Track(uri=u'uri1') track2 = Track(uri=u'uri2') From 69e6d5dc92cf3751844e057659e9ee3665bcf97a Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 23:25:35 +0200 Subject: [PATCH 09/34] Add test for equality with ordering changes of artists --- tests/models_test.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/models_test.py b/tests/models_test.py index eb7fa187..e5878bf0 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -91,6 +91,13 @@ class AlbumTest(unittest.TestCase): album2 = Album(artists=artists) self.assertEqual(album1, album2) + def test_eq_artists_order(self): + artist1 = Artist(name=u'name1') + artist2 = Artist(name=u'name2') + album1 = Album(artists=[artist1, artist2]) + album2 = Album(artists=[artist2, artist1]) + self.assertEqual(album1, album2) + def test_eq_num_tracks(self): album1 = Album(num_tracks=2) album2 = Album(num_tracks=2) @@ -241,6 +248,13 @@ class TrackTest(unittest.TestCase): track2 = Track(artists=artists) self.assertEqual(track1, track2) + def test_eq_artists_order(self): + artist1 = Artist(name=u'name1') + artist2 = Artist(name=u'name2') + track1 = Track(artists=[artist1, artist2]) + track2 = Track(artists=[artist2, artist1]) + self.assertEqual(track1, track2) + def test_eq_album(self): album = Album() track1 = Track(album=album) From fc45b20cca98fa0a956b90c071216728d4fdceff Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 23:26:02 +0200 Subject: [PATCH 10/34] Fix equality tests with respect to ordering --- mopidy/models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mopidy/models.py b/mopidy/models.py index 58077a31..66e085eb 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -64,7 +64,7 @@ class Album(ImmutableObject): num_tracks = 0 def __init__(self, *args, **kwargs): - self._artists = kwargs.pop('artists', []) + self._artists = set(kwargs.pop('artists', [])) super(Album, self).__init__(*args, **kwargs) def __eq__(self, other): @@ -79,7 +79,7 @@ class Album(ImmutableObject): @property def artists(self): """List of :class:`Artist` elements. Read-only.""" - return copy(self._artists) + return list(self._artists) class Track(ImmutableObject): @@ -129,7 +129,7 @@ class Track(ImmutableObject): id = None def __init__(self, *args, **kwargs): - self._artists = kwargs.pop('artists', []) + self._artists = set(kwargs.pop('artists', [])) super(Track, self).__init__(*args, **kwargs) def __eq__(self, other): @@ -144,7 +144,7 @@ class Track(ImmutableObject): @property def artists(self): """List of :class:`Artist`. Read-only.""" - return copy(self._artists) + return list(self._artists) def mpd_format(self, position=0, search_result=False): """ From 3a3ee1a9f946dab65d9717f16417a183f3c02633 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Tue, 27 Apr 2010 23:26:26 +0200 Subject: [PATCH 11/34] Fix MPD artist format with repsect to list to set conversion --- mopidy/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mopidy/models.py b/mopidy/models.py index 66e085eb..1c52cbd2 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -178,7 +178,9 @@ class Track(ImmutableObject): :rtype: string """ - return u', '.join([a.name for a in self.artists]) + artists = list(self._artists) + artists.sort(key=lambda a: a.name) + return u', '.join([a.name for a in artists]) class Playlist(ImmutableObject): From 1d3a394d032c57e39e41d1994f96ebfa21319e2b Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:36:13 +0200 Subject: [PATCH 12/34] =?UTF-8?q?=C2=ABHashable=20objects=20which=20compar?= =?UTF-8?q?e=20equal=20must=20have=20the=20same=20hash=20value=C2=BB=20ie.?= =?UTF-8?q?=20add=20hash=20tests=20for=20eq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/models_test.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/models_test.py b/tests/models_test.py index e5878bf0..0c3b2ca8 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -20,16 +20,19 @@ class ArtistTest(unittest.TestCase): artist1 = Artist(name=u'name') artist2 = Artist(name=u'name') self.assertEqual(artist1, artist2) + self.assertEqual(hash(artist1), hash(artist2)) def test_eq_uri(self): artist1 = Artist(uri=u'uri') artist2 = Artist(uri=u'uri') self.assertEqual(artist1, artist2) + self.assertEqual(hash(artist1), hash(artist2)) def test_eq(self): artist1 = Artist(uri=u'uri', name=u'name') artist2 = Artist(uri=u'uri', name=u'name') self.assertEqual(artist1, artist2) + self.assertEqual(hash(artist1), hash(artist2)) def test_eq_none(self): self.assertNotEqual(Artist(), None) @@ -38,17 +41,20 @@ class ArtistTest(unittest.TestCase): artist1 = Artist(name=u'name1') artist2 = Artist(name=u'name2') self.assertNotEqual(artist1, artist2) + self.assertNotEqual(hash(artist1), hash(artist2)) def test_ne_uri(self): artist1 = Artist(uri=u'uri1') artist2 = Artist(uri=u'uri2') self.assertNotEqual(artist1, artist2) + self.assertNotEqual(hash(artist1), hash(artist2)) def test_ne(self): artist1 = Artist(uri=u'uri1', name=u'name1') artist2 = Artist(uri=u'uri2', name=u'name2') self.assertNotEqual(artist1, artist2) - + self.assertNotEqual(hash(artist1), hash(artist2)) + class AlbumTest(unittest.TestCase): def test_uri(self): @@ -79,17 +85,20 @@ class AlbumTest(unittest.TestCase): album1 = Album(name=u'name') album2 = Album(name=u'name') self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq_uri(self): album1 = Album(uri=u'uri') album2 = Album(uri=u'uri') self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq_artists(self): artists = [Artist()] album1 = Album(artists=artists) album2 = Album(artists=artists) self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq_artists_order(self): artist1 = Artist(name=u'name1') @@ -97,17 +106,20 @@ class AlbumTest(unittest.TestCase): album1 = Album(artists=[artist1, artist2]) album2 = Album(artists=[artist2, artist1]) self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq_num_tracks(self): album1 = Album(num_tracks=2) album2 = Album(num_tracks=2) self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq(self): artists = [Artist()] album1 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2) album2 = Album(name=u'name', uri=u'uri', artists=artists, num_tracks=2) self.assertEqual(album1, album2) + self.assertEqual(hash(album1), hash(album2)) def test_eq_none(self): self.assertNotEqual(Album(), None) @@ -116,26 +128,31 @@ class AlbumTest(unittest.TestCase): album1 = Album(name=u'name1') album2 = Album(name=u'name2') self.assertNotEqual(album1, album2) + self.assertNotEqual(hash(album1), hash(album2)) def test_ne_uri(self): album1 = Album(uri=u'uri1') album2 = Album(uri=u'uri2') self.assertNotEqual(album1, album2) + self.assertNotEqual(hash(album1), hash(album2)) def test_ne_artists(self): album1 = Album(artists=[Artist(name=u'name1')]) album2 = Album(artists=[Artist(name=u'name2')]) self.assertNotEqual(album1, album2) + self.assertNotEqual(hash(album1), hash(album2)) def test_ne_num_tracks(self): album1 = Album(num_tracks=1) album2 = Album(num_tracks=2) self.assertNotEqual(album1, album2) + self.assertNotEqual(hash(album1), hash(album2)) def test_ne(self): album1 = Album(name=u'name1', uri=u'uri1', artists=[Artist(name=u'name1')], num_tracks=1) album2 = Album(name=u'name2', uri=u'uri2', artists=[Artist(name=u'name2')], num_tracks=2) self.assertNotEqual(album1, album2) + self.assertNotEqual(hash(album1), hash(album2)) class TrackTest(unittest.TestCase): @@ -236,17 +253,20 @@ class TrackTest(unittest.TestCase): track1 = Track(uri=u'uri1') track2 = Track(uri=u'uri1') self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_name(self): track1 = Track(name=u'name1') track2 = Track(name=u'name1') self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_artists(self): artists = [Artist()] track1 = Track(artists=artists) track2 = Track(artists=artists) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_artists_order(self): artist1 = Artist(name=u'name1') @@ -254,38 +274,45 @@ class TrackTest(unittest.TestCase): track1 = Track(artists=[artist1, artist2]) track2 = Track(artists=[artist2, artist1]) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_album(self): album = Album() track1 = Track(album=album) track2 = Track(album=album) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_track_no(self): track1 = Track(track_no=1) track2 = Track(track_no=1) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_date(self): date = dt.date.today() track1 = Track(date=date) track2 = Track(date=date) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_length(self): track1 = Track(length=100) track2 = Track(length=100) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_bitrate(self): track1 = Track(bitrate=100) track2 = Track(bitrate=100) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_id(self): track1 = Track(id=100) track2 = Track(id=100) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq(self): date = dt.date.today() @@ -296,6 +323,7 @@ class TrackTest(unittest.TestCase): track2 = Track(uri=u'uri', name=u'name', artists=artists, album=album, track_no=1, date=date, length=100, bitrate=100, id=2) self.assertEqual(track1, track2) + self.assertEqual(hash(track1), hash(track2)) def test_eq_none(self): self.assertNotEqual(Track(), None) @@ -304,46 +332,55 @@ class TrackTest(unittest.TestCase): track1 = Track(uri=u'uri1') track2 = Track(uri=u'uri2') self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_name(self): track1 = Track(name=u'name1') track2 = Track(name=u'name2') self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_artists(self): track1 = Track(artists=[Artist(name=u'name1')]) track2 = Track(artists=[Artist(name=u'name2')]) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_album(self): track1 = Track(album=Album(name=u'name1')) track2 = Track(album=Album(name=u'name2')) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_track_no(self): track1 = Track(track_no=1) track2 = Track(track_no=2) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_date(self): track1 = Track(date=dt.date.today()) track2 = Track(date=dt.date.today()-dt.timedelta(days=1)) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_length(self): track1 = Track(length=100) track2 = Track(length=200) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_bitrate(self): track1 = Track(bitrate=100) track2 = Track(bitrate=200) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne_id(self): track1 = Track(id=100) track2 = Track(id=200) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) def test_ne(self): track1 = Track(uri=u'uri1', name=u'name1', @@ -354,6 +391,7 @@ class TrackTest(unittest.TestCase): track_no=2, date=dt.date.today()-dt.timedelta(days=1), length=200, bitrate=200, id=1) self.assertNotEqual(track1, track2) + self.assertNotEqual(hash(track1), hash(track2)) class PlaylistTest(unittest.TestCase): From 64f81a659496491fe690d72c91c7be32730ceb3b Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:51:19 +0200 Subject: [PATCH 13/34] Add test_eq_other check --- tests/models_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/models_test.py b/tests/models_test.py index 0c3b2ca8..96f85d04 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -37,6 +37,9 @@ class ArtistTest(unittest.TestCase): def test_eq_none(self): self.assertNotEqual(Artist(), None) + def test_eq_other(self): + self.assertNotEqual(Artist(), 'other') + def test_ne_name(self): artist1 = Artist(name=u'name1') artist2 = Artist(name=u'name2') @@ -124,6 +127,9 @@ class AlbumTest(unittest.TestCase): def test_eq_none(self): self.assertNotEqual(Album(), None) + def test_eq_other(self): + self.assertNotEqual(Album(), 'other') + def test_ne_name(self): album1 = Album(name=u'name1') album2 = Album(name=u'name2') @@ -328,6 +334,9 @@ class TrackTest(unittest.TestCase): def test_eq_none(self): self.assertNotEqual(Track(), None) + def test_eq_other(self): + self.assertNotEqual(Track(), 'other') + def test_ne_uri(self): track1 = Track(uri=u'uri1') track2 = Track(uri=u'uri2') From 3c36efad5deab96ee24d2fd6d8c3b9600bdaaf31 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:52:05 +0200 Subject: [PATCH 14/34] Fix models with respect to comparison with other value --- mopidy/models.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mopidy/models.py b/mopidy/models.py index 1c52cbd2..c02babce 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -33,7 +33,7 @@ class Artist(ImmutableObject): name = None def __eq__(self, other): - if other is None: + if not isinstance(other, self.__class__): return False return self.__dict__ == other.__dict__ @@ -68,7 +68,7 @@ class Album(ImmutableObject): super(Album, self).__init__(*args, **kwargs) def __eq__(self, other): - if other is None: + if not isinstance(other, self.__class__): return False return self.__dict__ == other.__dict__ @@ -133,7 +133,7 @@ class Track(ImmutableObject): super(Track, self).__init__(*args, **kwargs) def __eq__(self, other): - if other is None: + if not isinstance(other, self.__class__): return False return self.__dict__ == other.__dict__ From 1e7fa943befd42a49d24125216e362ea6e97b6d6 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:52:40 +0200 Subject: [PATCH 15/34] Add hash function to models --- mopidy/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mopidy/models.py b/mopidy/models.py index c02babce..5f61f019 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -17,6 +17,12 @@ class ImmutableObject(object): return super(ImmutableObject, self).__setattr__(name, value) raise AttributeError('Object is immutable.') + def __hash__(self): + sum = 0 + for key,value in self.__dict__.items(): + sum += hash(key) + hash(value) + return sum + class Artist(ImmutableObject): """ From 949ca6357f8055c6cd4a3147759b9a91765ad327 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:53:10 +0200 Subject: [PATCH 16/34] Use frozensets in models as they are hashable --- mopidy/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/models.py b/mopidy/models.py index 5f61f019..67b60840 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -70,7 +70,7 @@ class Album(ImmutableObject): num_tracks = 0 def __init__(self, *args, **kwargs): - self._artists = set(kwargs.pop('artists', [])) + self._artists = frozenset(kwargs.pop('artists', [])) super(Album, self).__init__(*args, **kwargs) def __eq__(self, other): @@ -135,7 +135,7 @@ class Track(ImmutableObject): id = None def __init__(self, *args, **kwargs): - self._artists = set(kwargs.pop('artists', [])) + self._artists = frozenset(kwargs.pop('artists', [])) super(Track, self).__init__(*args, **kwargs) def __eq__(self, other): From db4ad726784abaeb1d6f7da3fc1b4af2eb1d35ba Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:53:51 +0200 Subject: [PATCH 17/34] Fix test_artists test with respect to hashing and set behaveviour --- tests/models_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/models_test.py b/tests/models_test.py index 96f85d04..4c554496 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -175,9 +175,9 @@ class TrackTest(unittest.TestCase): self.assertRaises(AttributeError, setattr, track, 'name', None) def test_artists(self): - artists = [Artist(), Artist()] + artists = [Artist(name=u'name1'), Artist(name=u'name2')] track = Track(artists=artists) - self.assertEqual(track.artists, artists) + self.assertEqual(set(track.artists), set(artists)) self.assertRaises(AttributeError, setattr, track, 'artists', None) def test_album(self): From 7ecc378bf9b33c5bbcb4c1a83d450569478f6ff3 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:54:06 +0200 Subject: [PATCH 18/34] Add fixme --- mopidy/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mopidy/utils.py b/mopidy/utils.py index 8edbc20d..9a23dd25 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -124,6 +124,7 @@ def parse_m3u(file_path): if line.startswith('#'): continue + # FIXME what about other URI types? if line.startswith('file://'): uris.append(line) else: From 3e640e1e5b73699bcc6f310f5a6f27e0faea3dc8 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:56:01 +0200 Subject: [PATCH 19/34] Move eq method to imutable object parent class --- mopidy/models.py | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/mopidy/models.py b/mopidy/models.py index 67b60840..d2b1e76a 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -23,6 +23,15 @@ class ImmutableObject(object): sum += hash(key) + hash(value) return sum + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + class Artist(ImmutableObject): """ @@ -38,15 +47,6 @@ class Artist(ImmutableObject): #: The artist name. Read-only. name = None - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not self.__eq__(other) - class Album(ImmutableObject): """ @@ -73,15 +73,6 @@ class Album(ImmutableObject): self._artists = frozenset(kwargs.pop('artists', [])) super(Album, self).__init__(*args, **kwargs) - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not self.__eq__(other) - @property def artists(self): """List of :class:`Artist` elements. Read-only.""" @@ -138,15 +129,6 @@ class Track(ImmutableObject): self._artists = frozenset(kwargs.pop('artists', [])) super(Track, self).__init__(*args, **kwargs) - def __eq__(self, other): - if not isinstance(other, self.__class__): - return False - - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - return not self.__eq__(other) - @property def artists(self): """List of :class:`Artist`. Read-only.""" From 7158056c26ed3a1a7c0d20f80d8df3ce4fe87637 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 21:57:53 +0200 Subject: [PATCH 20/34] Test id() for equality, not playlists them selves due to eq changes --- tests/backends/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/backends/base.py b/tests/backends/base.py index a03ea95d..b9c1a389 100644 --- a/tests/backends/base.py +++ b/tests/backends/base.py @@ -96,7 +96,7 @@ class BaseCurrentPlaylistControllerTest(object): def test_load(self): new_playlist = Playlist() - self.assertNotEqual(new_playlist, self.controller.playlist) + self.assertNotEqual(id(new_playlist), id(self.controller.playlist)) self.controller.load(new_playlist) # FIXME how do we test this without going into internals? self.assertEqual(new_playlist, self.controller._playlist) @@ -175,7 +175,7 @@ class BaseCurrentPlaylistControllerTest(object): playlist1 = self.controller.playlist playlist2 = self.controller.playlist - self.assertNotEqual(playlist1, playlist2) + self.assertNotEqual(id(playlist1), id(playlist2)) @populate_playlist def test_remove(self): From f36f64c6ca81a56a752b1cba6c0e7ce34450d6f1 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:02:01 +0200 Subject: [PATCH 21/34] Add basic mpd tag cache parser and tests --- mopidy/utils.py | 68 +++++++++++++++++++++++++++++++++++++ tests/data/empty_tag_cache | 6 ++++ tests/data/simple_tag_cache | 15 ++++++++ tests/utils_test.py | 45 +++++++++++++++++++++++- 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 tests/data/empty_tag_cache create mode 100644 tests/data/simple_tag_cache diff --git a/mopidy/utils.py b/mopidy/utils.py index 9a23dd25..fe651f45 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -6,6 +6,8 @@ import urllib logger = logging.getLogger('mopidy.utils') +from mopidy.models import Track, Artist, Album + def flatten(the_list): result = [] for element in the_list: @@ -133,3 +135,69 @@ def parse_m3u(file_path): uris.append('file://' + path) return uris + +def parse_mpd_tag_cache(tag_cache, music_dir=''): + """ + Converts a MPD tag_cache into a lists of tracks, artists and albums. + """ + with open(tag_cache) as library: + contents = library.read() + + tracks = set() + artists = set() + albums = set() + current = {} + state = None + + for line in contents.split('\n'): + if line == 'songList begin': + state = 'songs' + continue + elif line == 'songList end': + state = None + continue + elif not state: + continue + + key, value = line.split(': ', 1) + + if key == 'key': + _convert_mpd_data(current, tracks, artists, albums, music_dir) + current.clear() + + current[key.lower()] = value + + _convert_mpd_data(current, tracks, artists, albums, music_dir) + + return tracks, artists, albums + +def _convert_mpd_data(data, tracks, artists, albums, music_dir): + if not data: + return + + match = filter(lambda a: a.name == data['artist'], artists) + if match: + artist = match[0] + else: + artist = Artist(name=data['artist']) + print 'adding %s' % artist + artists.add(artist) + + match = filter(lambda a: a.name == data['album'], albums) + if match: + album = match[0] + else: + num_tracks = int(data['track'].split('/')[1]) + album = Album(name=data['album'], artists=[artist], num_tracks=num_tracks) + print 'adding %s' % album + albums.add(album) + + match = filter(lambda t: t.name == data['title'], tracks) + if not match: + path = os.path.join(music_dir, data['file'][1:]) + uri = 'file://' + urllib.pathname2url(path) + track_no = int(data['track'].split('/')[0]) + track = Track(name=data['title'], artists=[artist], track_no=track_no, + length=int(data['time'])*1000, uri=uri, album=album) + print 'adding %s' % track + tracks.add(track) diff --git a/tests/data/empty_tag_cache b/tests/data/empty_tag_cache new file mode 100644 index 00000000..84053d90 --- /dev/null +++ b/tests/data/empty_tag_cache @@ -0,0 +1,6 @@ +info_begin +mpd_version: 0.14.2 +fs_charset: UTF-8 +info_end +songList begin +songList end diff --git a/tests/data/simple_tag_cache b/tests/data/simple_tag_cache new file mode 100644 index 00000000..cc71ac6d --- /dev/null +++ b/tests/data/simple_tag_cache @@ -0,0 +1,15 @@ +info_begin +mpd_version: 0.14.2 +fs_charset: UTF-8 +info_end +songList begin +key: song1.mp3 +file: /song1.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +songList end diff --git a/tests/utils_test.py b/tests/utils_test.py index 0cc8f1f4..840f2c0c 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -5,7 +5,8 @@ import tempfile import unittest import urllib -from mopidy.utils import parse_m3u +from mopidy.utils import parse_m3u, parse_mpd_tag_cache +from mopidy.models import Track, Artist, Album def data(name): folder = os.path.dirname(__file__) @@ -61,3 +62,45 @@ class M3UToUriTest(unittest.TestCase): def test_encoding_is_latin1(self): uris = parse_m3u(data('encoding.m3u')) self.assertEqual([encoded_uri], uris) + +expected_artists = [Artist(name='name')] +expected_albums = [Album(name='albumname', artists=expected_artists, num_tracks=2)] +expected_tracks = [] + +def generate_track(path): + uri = 'file://' + urllib.pathname2url(data(path)) + track = Track(name='trackname', artists=expected_artists, track_no=1, + album=expected_albums[0], length=4000, uri=uri) + expected_tracks.append(track) + +generate_track('song1.mp3') +generate_track('song2.mp3') +generate_track('song3.mp3') +generate_track('subdir1/song4.mp3') +generate_track('subdir1/song5.mp3') +generate_track('subdir2/song6.mp3') +generate_track('subdir2/song7.mp3') +generate_track('subdir1/subsubdir/song8.mp3') +generate_track('subdir1/subsubdir/song9.mp3') + +class MPDTagCacheToTracksTest(unittest.TestCase): + def test_emtpy_cache(self): + tracks, artists, albums = parse_mpd_tag_cache(data('empty_tag_cache'), data('')) + self.assertEqual(set(), tracks) + self.assertEqual(set(), artists) + self.assertEqual(set(), albums) + + def test_simple_cache(self): + tracks, artists, albums = parse_mpd_tag_cache(data('simple_tag_cache'), data('')) + + track1 = expected_tracks[0] + track2 = list(tracks)[0] + + self.assertEqual(track1.album._artists, track2.album._artists) + self.assertEqual(track1.album.name, track2.album.name) + self.assertEqual(track1.album.num_tracks, track2.album.num_tracks) + self.assertEqual(track1.artists, track2.artists) + self.assertEqual(track1, track2) + + self.assertEqual(set(expected_artists), artists) + self.assertEqual(set(expected_albums), albums) From 3b3ba18966bcd389fab3fa5c7499f3b17e29f41b Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:03:14 +0200 Subject: [PATCH 22/34] Simplify MPD tag cache code --- mopidy/utils.py | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/mopidy/utils.py b/mopidy/utils.py index fe651f45..3a5b717a 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -175,29 +175,17 @@ def _convert_mpd_data(data, tracks, artists, albums, music_dir): if not data: return - match = filter(lambda a: a.name == data['artist'], artists) - if match: - artist = match[0] - else: - artist = Artist(name=data['artist']) - print 'adding %s' % artist - artists.add(artist) + num_tracks = int(data['track'].split('/')[1]) + track_no = int(data['track'].split('/')[0]) + path = os.path.join(music_dir, data['file'][1:]) + uri = 'file://' + urllib.pathname2url(path) - match = filter(lambda a: a.name == data['album'], albums) - if match: - album = match[0] - else: - num_tracks = int(data['track'].split('/')[1]) - album = Album(name=data['album'], artists=[artist], num_tracks=num_tracks) - print 'adding %s' % album - albums.add(album) + artist = Artist(name=data['artist']) + artists.add(artist) - match = filter(lambda t: t.name == data['title'], tracks) - if not match: - path = os.path.join(music_dir, data['file'][1:]) - uri = 'file://' + urllib.pathname2url(path) - track_no = int(data['track'].split('/')[0]) - track = Track(name=data['title'], artists=[artist], track_no=track_no, - length=int(data['time'])*1000, uri=uri, album=album) - print 'adding %s' % track - tracks.add(track) + album = Album(name=data['album'], artists=[artist], num_tracks=num_tracks) + albums.add(album) + + track = Track(name=data['title'], artists=[artist], track_no=track_no, + length=int(data['time'])*1000, uri=uri, album=album) + tracks.add(track) From 853af8a4921d57269f7639a12cb533ccbabe5a15 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:09:30 +0200 Subject: [PATCH 23/34] Add fixme and test stub for playlist eq and hash testing --- tests/models_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/models_test.py b/tests/models_test.py index 4c554496..78c28bd2 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -3,6 +3,8 @@ import unittest from mopidy.models import Artist, Album, Track, Playlist +from tests import SkipTest + class ArtistTest(unittest.TestCase): def test_uri(self): uri = u'an_uri' @@ -506,3 +508,7 @@ class PlaylistTest(unittest.TestCase): self.assertEqual(new_playlist.name, u'a name') self.assertEqual(new_playlist.tracks, tracks) self.assertEqual(new_playlist.last_modified, new_last_modified) + + def test_eq(self): + # FIXME missing all equal and hash tests + raise SkipTest From b6340d107bc5e1e9e0f8cd48e30b7716af7d92fb Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:30:26 +0200 Subject: [PATCH 24/34] Clean mpd tag cache tests --- tests/utils_test.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tests/utils_test.py b/tests/utils_test.py index 840f2c0c..3e88fc3b 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -85,22 +85,16 @@ generate_track('subdir1/subsubdir/song9.mp3') class MPDTagCacheToTracksTest(unittest.TestCase): def test_emtpy_cache(self): - tracks, artists, albums = parse_mpd_tag_cache(data('empty_tag_cache'), data('')) + tracks, artists, albums = parse_mpd_tag_cache(data('empty_tag_cache'), + data('')) self.assertEqual(set(), tracks) self.assertEqual(set(), artists) self.assertEqual(set(), albums) def test_simple_cache(self): - tracks, artists, albums = parse_mpd_tag_cache(data('simple_tag_cache'), data('')) - - track1 = expected_tracks[0] - track2 = list(tracks)[0] - - self.assertEqual(track1.album._artists, track2.album._artists) - self.assertEqual(track1.album.name, track2.album.name) - self.assertEqual(track1.album.num_tracks, track2.album.num_tracks) - self.assertEqual(track1.artists, track2.artists) - self.assertEqual(track1, track2) + tracks, artists, albums = parse_mpd_tag_cache(data('simple_tag_cache'), + data('')) + self.assertEqual(expected_tracks[0], list(tracks)[0]) self.assertEqual(set(expected_artists), artists) self.assertEqual(set(expected_albums), albums) From 837f35ef364fe36e188716bcd773526227dc06f5 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:31:08 +0200 Subject: [PATCH 25/34] Add advanced tag cache test --- tests/data/advanced_tag_cache | 102 ++++++++++++++++++++++++++++++++++ tests/utils_test.py | 8 +++ 2 files changed, 110 insertions(+) create mode 100644 tests/data/advanced_tag_cache diff --git a/tests/data/advanced_tag_cache b/tests/data/advanced_tag_cache new file mode 100644 index 00000000..3288275f --- /dev/null +++ b/tests/data/advanced_tag_cache @@ -0,0 +1,102 @@ +info_begin +mpd_version: 0.14.2 +fs_charset: UTF-8 +info_end +directory: subdir1 +begin: subdir1 +directory: subsubdir +begin: subdir1/subsubdir +songList begin +key: song8.mp3 +file: subdir1/subsubdir/song8.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +key: song9.mp3 +file: subdir1/subsubdir/song9.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +songList end +end: subdir1/subsubdir +songList begin +key: song4.mp3 +file: subdir1/song4.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +key: song5.mp3 +file: subdir1/song5.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +songList end +end: subdir1 +directory: subdir2 +begin: subdir2 +songList begin +key: song6.mp3 +file: subdir2/song6.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +key: song7.mp3 +file: subdir2/song7.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +songList end +end: subdir2 +songList begin +key: song1.mp3 +file: /song1.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +key: song2.mp3 +file: /song2.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +key: song3.mp3 +file: /song3.mp3 +Time: 4 +Artist: name +Title: trackname +Album: albumname +Track: 1/2 +Date: 2006 +mtime: 1272319626 +songList end diff --git a/tests/utils_test.py b/tests/utils_test.py index 3e88fc3b..cdfb47a0 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -98,3 +98,11 @@ class MPDTagCacheToTracksTest(unittest.TestCase): self.assertEqual(expected_tracks[0], list(tracks)[0]) self.assertEqual(set(expected_artists), artists) self.assertEqual(set(expected_albums), albums) + + def test_advanced_cache(self): + tracks, artists, albums = parse_mpd_tag_cache(data('advanced_tag_cache'), + data('')) + + self.assertEqual(set(expected_tracks), tracks) + self.assertEqual(set(expected_artists), artists) + self.assertEqual(set(expected_albums), albums) From febdbce0e1ef9dc9b72b363944d48f84b32083e3 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:31:25 +0200 Subject: [PATCH 26/34] Fix mpd tag cache code with respect to newest test --- mopidy/utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mopidy/utils.py b/mopidy/utils.py index 3a5b717a..19c33790 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -177,7 +177,12 @@ def _convert_mpd_data(data, tracks, artists, albums, music_dir): num_tracks = int(data['track'].split('/')[1]) track_no = int(data['track'].split('/')[0]) - path = os.path.join(music_dir, data['file'][1:]) + path = data['file'] + + if path[0] == '/': + path = path[1:] + + path = os.path.join(music_dir, path) uri = 'file://' + urllib.pathname2url(path) artist = Artist(name=data['artist']) From 15751613a10af6d83d38488253dfef3b58643ec9 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:41:37 +0200 Subject: [PATCH 27/34] Add some test stubs for mpd cache handling --- tests/utils_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/utils_test.py b/tests/utils_test.py index cdfb47a0..17f8282c 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -106,3 +106,10 @@ class MPDTagCacheToTracksTest(unittest.TestCase): self.assertEqual(set(expected_tracks), tracks) self.assertEqual(set(expected_artists), artists) self.assertEqual(set(expected_albums), albums) + + def test_unicode_cache(self): + raise SkipTest + + def test_misencoded_cache(self): + # FIXME not sure if this can happen + raise SkipTest From 5f08dbc213c80c7fca4fab46d67e11fbf30e0978 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:45:36 +0200 Subject: [PATCH 28/34] Add extra settings for music folder and tag cache --- mopidy/settings.py | 6 ++++++ tests/utils_test.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/mopidy/settings.py b/mopidy/settings.py index ce132ba7..d160b26c 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -104,6 +104,12 @@ SPOTIFY_LIB_CACHE = u'~/.mopidy/libspotify_cache' #: Path to playlist folder with m3u files. PLAYLIST_FOLDER = u'~/.mopidy/playlists' +#: Path to folder with local music. +MUSIC_FOLDER = u'~/music' + +#: Path to MPD tag_cache for local music +TAG_CACHE = u'~/.mopidy/tag_cache' + # Import user specific settings dotdir = os.path.expanduser(u'~/.mopidy/') settings_file = os.path.join(dotdir, u'settings.py') diff --git a/tests/utils_test.py b/tests/utils_test.py index 17f8282c..3952a7d6 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -8,6 +8,8 @@ import urllib from mopidy.utils import parse_m3u, parse_mpd_tag_cache from mopidy.models import Track, Artist, Album +from tests import SkipTest + def data(name): folder = os.path.dirname(__file__) folder = os.path.join(folder, 'data') From 074da2e54288f2f3090c02c9f58587bbf34ed535 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 22:56:10 +0200 Subject: [PATCH 29/34] Add minimal BaseLibraryControllerTest --- tests/backends/base.py | 12 +++++++++++- tests/backends/gstreamer_test.py | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/backends/base.py b/tests/backends/base.py index b9c1a389..67498788 100644 --- a/tests/backends/base.py +++ b/tests/backends/base.py @@ -13,7 +13,8 @@ from tests import SkipTest __all__ = ['BaseCurrentPlaylistControllerTest', 'BasePlaybackControllerTest', - 'BaseStoredPlaylistsControllerTest'] + 'BaseStoredPlaylistsControllerTest', + 'BaseLibraryControllerTest'] def populate_playlist(func): def wrapper(self): @@ -963,3 +964,12 @@ class BaseStoredPlaylistsControllerTest(object): playlist = Playlist(name='test') self.stored.save(playlist) self.assert_(playlist in self.stored.playlists) + + +class BaseLibraryControllerTest(object): + def setUp(self): + self.backend = self.backend_class(mixer=DummyMixer()) + self.controller = self.backend.library + + def tearDown(self): + self.backend.destroy() diff --git a/tests/backends/gstreamer_test.py b/tests/backends/gstreamer_test.py index 6d010b9b..78c591aa 100644 --- a/tests/backends/gstreamer_test.py +++ b/tests/backends/gstreamer_test.py @@ -121,5 +121,12 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle def test_save_sets_playlist_uri(self): raise SkipTest + +class GStreamerBackendLibraryControllerTest(BaseStoredPlaylistsControllerTest, + unittest.TestCase): + + backend_class = GStreamerBackend + + if __name__ == '__main__': unittest.main() From 42e96ebdcddc1a81b1c7b07894a7339eb9e956be Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 28 Apr 2010 23:04:39 +0200 Subject: [PATCH 30/34] Add placeholders for library tests --- tests/backends/base.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/backends/base.py b/tests/backends/base.py index 67498788..66baa9db 100644 --- a/tests/backends/base.py +++ b/tests/backends/base.py @@ -973,3 +973,42 @@ class BaseLibraryControllerTest(object): def tearDown(self): self.backend.destroy() + + def test_refresh(self): + raise SkipTest + + def test_lookup(self): + raise SkipTest + + def test_lookup_unknown_track(self): + raise SkipTest + + def test_find_exact_no_hits(self): + raise SkipTest + + def test_find_exact_artist(self): + raise SkipTest + + def test_find_exact_track(self): + raise SkipTest + + def test_find_exact_album(self): + raise SkipTest + + def test_find_search_no_hits(self): + raise SkipTest + + def test_find_search_artist(self): + raise SkipTest + + def test_find_search_track(self): + raise SkipTest + + def test_find_search_album(self): + raise SkipTest + + def test_find_search_uri(self): + raise SkipTest + + def test_find_search_any(self): + raise SkipTest From a0fae47e902f06aa92dd132dc45ae203a930319e Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Thu, 29 Apr 2010 20:01:35 +0200 Subject: [PATCH 31/34] Ensure that renamed playlists aren't created --- tests/backends/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/backends/base.py b/tests/backends/base.py index 66baa9db..16d616e9 100644 --- a/tests/backends/base.py +++ b/tests/backends/base.py @@ -958,6 +958,8 @@ class BaseStoredPlaylistsControllerTest(object): def test_rename_unknown_playlist(self): self.stored.rename(Playlist(), 'test2') + test = lambda: self.stored.get(name='test2') + self.assertRaises(LookupError, test) def test_save(self): # FIXME should we handle playlists without names? From 53bc3cec6ae191215cc1b74f06da721523b230dc Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Thu, 29 Apr 2010 20:03:08 +0200 Subject: [PATCH 32/34] Ensure the files don't exist before in playlist tests --- tests/backends/gstreamer_test.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/backends/gstreamer_test.py b/tests/backends/gstreamer_test.py index 78c591aa..8dc454c4 100644 --- a/tests/backends/gstreamer_test.py +++ b/tests/backends/gstreamer_test.py @@ -57,14 +57,16 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle backend_class = GStreamerBackend def test_created_playlist_is_persisted(self): + path = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u') + self.assert_(not os.path.exists(path)) self.stored.create('test') - file = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u') - self.assert_(os.path.exists(file)) + self.assert_(os.path.exists(path)) def test_saved_playlist_is_persisted(self): + path = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u') + self.assert_(not os.path.exists(path)) self.stored.save(Playlist(name='test2')) - file = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u') - self.assert_(os.path.exists(file)) + self.assert_(os.path.exists(path)) def test_deleted_playlist_get_removed(self): playlist = self.stored.create('test') @@ -74,9 +76,10 @@ class GStreamerBackendStoredPlaylistsControllerTest(BaseStoredPlaylistsControlle def test_renamed_playlist_gets_moved(self): playlist = self.stored.create('test') - self.stored.rename(playlist, 'test2') file1 = os.path.join(settings.PLAYLIST_FOLDER, 'test.m3u') file2 = os.path.join(settings.PLAYLIST_FOLDER, 'test2.m3u') + self.assert_(not os.path.exists(file2)) + self.stored.rename(playlist, 'test2') self.assert_(not os.path.exists(file1)) self.assert_(os.path.exists(file2)) From 0bcda9920bd4abb7d4e9791d6aa984aedd09afd8 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Thu, 29 Apr 2010 20:37:22 +0200 Subject: [PATCH 33/34] Various pylint fixes --- mopidy/backends/__init__.py | 6 ++++-- mopidy/mixers/denon.py | 2 +- mopidy/mixers/osa.py | 2 +- mopidy/models.py | 8 ++++---- mopidy/mpd/frontend.py | 2 +- mopidy/settings.py | 3 ++- mopidy/utils.py | 4 ++-- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/mopidy/backends/__init__.py b/mopidy/backends/__init__.py index f7705f64..611c88d4 100644 --- a/mopidy/backends/__init__.py +++ b/mopidy/backends/__init__.py @@ -176,7 +176,8 @@ class BaseCurrentPlaylistController(object): assert start >= 0, 'start must be at least zero' assert end <= len(tracks), 'end can not be larger than playlist length' assert to_position >= 0, 'to_position must be at least zero' - assert to_position <= len(tracks), 'to_position can not be larger than playlist length' + assert to_position <= len(tracks), 'to_position can not be larger ' + \ + 'than playlist length' new_tracks = tracks[:start] + tracks[end:] for track in tracks[start:end]: @@ -218,7 +219,8 @@ class BaseCurrentPlaylistController(object): assert start >= 0, 'start must be at least zero' if end is not None: - assert end <= len(tracks), 'end can not be larger than playlist length' + assert end <= len(tracks), 'end can not be larger than ' + \ + 'playlist length' before = tracks[:start or 0] shuffled = tracks[start:end] diff --git a/mopidy/mixers/denon.py b/mopidy/mixers/denon.py index 9d065d9a..3218dbe5 100644 --- a/mopidy/mixers/denon.py +++ b/mopidy/mixers/denon.py @@ -37,7 +37,7 @@ class DenonMixer(BaseMixer): self._lock = Lock() def _get_volume(self): - self._lock.acquire(); + self._lock.acquire() self.ensure_open_device() self._device.write('MV?\r') vol = str(self._device.readline()[2:4]) diff --git a/mopidy/mixers/osa.py b/mopidy/mixers/osa.py index 6291cac1..3aeaed5c 100644 --- a/mopidy/mixers/osa.py +++ b/mopidy/mixers/osa.py @@ -17,7 +17,7 @@ class OsaMixer(BaseMixer): and (int(time.time() - self._last_update) < self.CACHE_TTL)) def _get_volume(self): - if not self._valid_cache(): + if not self._valid_cache(): try: self._cache = int(Popen( ['osascript', '-e', diff --git a/mopidy/models.py b/mopidy/models.py index d2b1e76a..b9c73783 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -18,10 +18,10 @@ class ImmutableObject(object): raise AttributeError('Object is immutable.') def __hash__(self): - sum = 0 - for key,value in self.__dict__.items(): - sum += hash(key) + hash(value) - return sum + hash_sum = 0 + for key, value in self.__dict__.items(): + hash_sum += hash(key) + hash(value) + return hash_sum def __eq__(self, other): if not isinstance(other, self.__class__): diff --git a/mopidy/mpd/frontend.py b/mopidy/mpd/frontend.py index c2ac84ea..21d1752b 100644 --- a/mopidy/mpd/frontend.py +++ b/mopidy/mpd/frontend.py @@ -643,7 +643,7 @@ class MpdFrontend(object): - capitalizes the type argument. """ type = type.lower() - pass # TODO + # TODO @handle_pattern(r'^listall "(?P[^"]+)"') def _music_db_listall(self, uri): diff --git a/mopidy/settings.py b/mopidy/settings.py index d160b26c..886e7189 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -26,7 +26,8 @@ BACKENDS = ( #: The log format used on the console. See #: http://docs.python.org/library/logging.html#formatter-objects for details on #: the format. -CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s [%(process)d:%(threadName)s] %(name)s\n %(message)s' +CONSOLE_LOG_FORMAT = u'%(levelname)-8s %(asctime)s' + \ + ' [%(process)d:%(threadName)s] %(name)s\n %(message)s' #: Protocol frontend to use. Default:: #: diff --git a/mopidy/utils.py b/mopidy/utils.py index 19c33790..3b5de37d 100644 --- a/mopidy/utils.py +++ b/mopidy/utils.py @@ -130,8 +130,8 @@ def parse_m3u(file_path): if line.startswith('file://'): uris.append(line) else: - file = os.path.join(folder, line) - path = urllib.pathname2url(file.encode('utf-8')) + path = os.path.join(folder, line) + path = urllib.pathname2url(path.encode('utf-8')) uris.append('file://' + path) return uris From 1da9dced7750b92a2a4a8654c8827ca78100d781 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Thu, 29 Apr 2010 21:09:17 +0200 Subject: [PATCH 34/34] Ensure that models don't accept unknown kwarg keys --- mopidy/models.py | 6 +++++- tests/models_test.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mopidy/models.py b/mopidy/models.py index b9c73783..42344677 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -10,7 +10,11 @@ class ImmutableObject(object): """ def __init__(self, *args, **kwargs): - self.__dict__.update(kwargs) + for key, value in kwargs.items(): + if not hasattr(self, key): + raise TypeError('__init__() got an unexpected keyword ' + \ + 'argument \'%s\'' % key) + self.__dict__[key] = value def __setattr__(self, name, value): if name.startswith('_'): diff --git a/tests/models_test.py b/tests/models_test.py index 78c28bd2..ced716f2 100644 --- a/tests/models_test.py +++ b/tests/models_test.py @@ -18,6 +18,10 @@ class ArtistTest(unittest.TestCase): self.assertEqual(artist.name, name) self.assertRaises(AttributeError, setattr, artist, 'name', None) + def test_invalid_kwarg(self): + test = lambda: Artist(foo='baz') + self.assertRaises(TypeError, test) + def test_eq_name(self): artist1 = Artist(name=u'name') artist2 = Artist(name=u'name') @@ -86,6 +90,10 @@ class AlbumTest(unittest.TestCase): self.assertEqual(album.num_tracks, num_tracks) self.assertRaises(AttributeError, setattr, album, 'num_tracks', None) + def test_invalid_kwarg(self): + test = lambda: Album(foo='baz') + self.assertRaises(TypeError, test) + def test_eq_name(self): album1 = Album(name=u'name') album2 = Album(name=u'name') @@ -257,6 +265,10 @@ class TrackTest(unittest.TestCase): track = Track(artists=[Artist(name=u'ABBA'), Artist(name=u'Beatles')]) self.assertEqual(track.mpd_format_artists(), u'ABBA, Beatles') + def test_invalid_kwarg(self): + test = lambda: Track(foo='baz') + self.assertRaises(TypeError, test) + def test_eq_uri(self): track1 = Track(uri=u'uri1') track2 = Track(uri=u'uri1') @@ -509,6 +521,10 @@ class PlaylistTest(unittest.TestCase): self.assertEqual(new_playlist.tracks, tracks) self.assertEqual(new_playlist.last_modified, new_last_modified) + def test_invalid_kwarg(self): + test = lambda: Playlist(foo='baz') + self.assertRaises(TypeError, test) + def test_eq(self): # FIXME missing all equal and hash tests raise SkipTest