From c452f0115a386db2e8aa89d26f0a6b877241ba93 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 5 Apr 2013 16:07:00 +0200 Subject: [PATCH] mpd: Use new config system --- mopidy/frontends/mpd/actor.py | 15 +++--- mopidy/frontends/mpd/dispatcher.py | 15 ++++-- mopidy/frontends/mpd/protocol/connection.py | 3 +- mopidy/frontends/mpd/session.py | 5 +- mopidy/frontends/mpd/translator.py | 21 ++++---- mopidy/scanner.py | 4 +- tests/frontends/mpd/dispatcher_test.py | 7 ++- tests/frontends/mpd/protocol/__init__.py | 10 +++- .../mpd/protocol/authentication_test.py | 41 ++++++-------- .../frontends/mpd/protocol/connection_test.py | 17 ------ .../frontends/mpd/protocol/reflection_test.py | 53 ++++++++++--------- tests/frontends/mpd/translator_test.py | 46 +++++++--------- 12 files changed, 117 insertions(+), 120 deletions(-) diff --git a/mopidy/frontends/mpd/actor.py b/mopidy/frontends/mpd/actor.py index e288c24e..45ed753e 100644 --- a/mopidy/frontends/mpd/actor.py +++ b/mopidy/frontends/mpd/actor.py @@ -5,7 +5,6 @@ import sys import pykka -from mopidy import settings from mopidy.core import CoreListener from mopidy.frontends.mpd import session from mopidy.utils import encoding, network, process @@ -16,17 +15,21 @@ logger = logging.getLogger('mopidy.frontends.mpd') class MpdFrontend(pykka.ThreadingActor, CoreListener): def __init__(self, config, core): super(MpdFrontend, self).__init__() - hostname = network.format_hostname(settings.MPD_SERVER_HOSTNAME) - port = settings.MPD_SERVER_PORT + hostname = network.format_hostname(config['mpd']['hostname']) + port = config['mpd']['port'] # NOTE kwargs dict keys must be bytestrings to work on Python < 2.6.5 # See https://github.com/mopidy/mopidy/issues/302 for details. try: network.Server( hostname, port, - protocol=session.MpdSession, protocol_kwargs={b'core': core}, - max_connections=settings.MPD_SERVER_MAX_CONNECTIONS, - timeout=settings.MPD_SERVER_CONNECTION_TIMEOUT) + protocol=session.MpdSession, + protocol_kwargs={ + b'config': config, + b'core': core, + }, + max_connections=config['mpd']['max_connections'], + timeout=config['mpd']['connection_timeout']) except IOError as error: logger.error( 'MPD server startup failed: %s', diff --git a/mopidy/frontends/mpd/dispatcher.py b/mopidy/frontends/mpd/dispatcher.py index 4f0001ac..dc665abc 100644 --- a/mopidy/frontends/mpd/dispatcher.py +++ b/mopidy/frontends/mpd/dispatcher.py @@ -5,7 +5,6 @@ import re import pykka -from mopidy import settings from mopidy.frontends.mpd import exceptions, protocol logger = logging.getLogger('mopidy.frontends.mpd.dispatcher') @@ -22,13 +21,15 @@ class MpdDispatcher(object): _noidle = re.compile(r'^noidle$') - def __init__(self, session=None, core=None): + def __init__(self, session=None, config=None, core=None): + self.config = config self.authenticated = False self.command_list_receiving = False self.command_list_ok = False self.command_list = [] self.command_list_index = None - self.context = MpdContext(self, session=session, core=core) + self.context = MpdContext( + self, session=session, config=config, core=core) def handle_request(self, request, current_command_list_index=None): """Dispatch incoming requests to the correct handler.""" @@ -82,7 +83,7 @@ class MpdDispatcher(object): def _authenticate_filter(self, request, response, filter_chain): if self.authenticated: return self._call_next_filter(request, response, filter_chain) - elif settings.MPD_SERVER_PASSWORD is None: + elif self.config['mpd']['password'] is None: self.authenticated = True return self._call_next_filter(request, response, filter_chain) else: @@ -223,6 +224,9 @@ class MpdContext(object): #: The current :class:`mopidy.frontends.mpd.MpdSession`. session = None + #: The Mopidy configuration. + config = None + #: The Mopidy core API. An instance of :class:`mopidy.core.Core`. core = None @@ -232,9 +236,10 @@ class MpdContext(object): #: The subsytems that we want to be notified about in idle mode. subscriptions = None - def __init__(self, dispatcher, session=None, core=None): + def __init__(self, dispatcher, session=None, config=None, core=None): self.dispatcher = dispatcher self.session = session + self.config = config self.core = core self.events = set() self.subscriptions = set() diff --git a/mopidy/frontends/mpd/protocol/connection.py b/mopidy/frontends/mpd/protocol/connection.py index f7898d21..44696705 100644 --- a/mopidy/frontends/mpd/protocol/connection.py +++ b/mopidy/frontends/mpd/protocol/connection.py @@ -1,6 +1,5 @@ from __future__ import unicode_literals -from mopidy import settings from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.exceptions import ( MpdPasswordError, MpdPermissionError) @@ -40,7 +39,7 @@ def password_(context, password): This is used for authentication with the server. ``PASSWORD`` is simply the plaintext password. """ - if password == settings.MPD_SERVER_PASSWORD: + if password == context.config['mpd']['password']: context.dispatcher.authenticated = True else: raise MpdPasswordError('incorrect password', command='password') diff --git a/mopidy/frontends/mpd/session.py b/mopidy/frontends/mpd/session.py index 8a5deecd..14173308 100644 --- a/mopidy/frontends/mpd/session.py +++ b/mopidy/frontends/mpd/session.py @@ -18,9 +18,10 @@ class MpdSession(network.LineProtocol): encoding = protocol.ENCODING delimiter = r'\r?\n' - def __init__(self, connection, core=None): + def __init__(self, connection, config=None, core=None): super(MpdSession, self).__init__(connection) - self.dispatcher = dispatcher.MpdDispatcher(session=self, core=core) + self.dispatcher = dispatcher.MpdDispatcher( + session=self, config=config, core=core) def on_start(self): logger.info('New MPD connection from [%s]:%s', self.host, self.port) diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index 15ca181d..d820b0e0 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -5,7 +5,6 @@ import re import shlex import urllib -from mopidy import settings from mopidy.frontends.mpd import protocol from mopidy.frontends.mpd.exceptions import MpdArgError from mopidy.models import TlTrack @@ -216,12 +215,14 @@ def query_from_mpd_search_format(mpd_query): return query -def tracks_to_tag_cache_format(tracks): +def tracks_to_tag_cache_format(tracks, music_path): """ Format list of tracks for output to MPD tag cache :param tracks: the tracks :type tracks: list of :class:`mopidy.models.Track` + :param music_path: the path to the music dir + :type music_path: string :rtype: list of lists of two-tuples """ result = [ @@ -231,14 +232,15 @@ def tracks_to_tag_cache_format(tracks): ('info_end',) ] tracks.sort(key=lambda t: t.uri) - _add_to_tag_cache(result, *tracks_to_directory_tree(tracks)) + folders, files = tracks_to_directory_tree(tracks, music_path) + _add_to_tag_cache(result, folders, files, music_path) return result -def _add_to_tag_cache(result, folders, files): - base_path = settings.LOCAL_MUSIC_PATH.encode('utf-8') +def _add_to_tag_cache(result, folders, files, music_path): + base_path = music_path.encode('utf-8') - for path, entry in folders.items(): + for path, (entry_folders, entry_files) in folders.items(): try: text_path = path.decode('utf-8') except UnicodeDecodeError: @@ -247,7 +249,7 @@ def _add_to_tag_cache(result, folders, files): result.append(('directory', text_path)) result.append(('mtime', get_mtime(os.path.join(base_path, path)))) result.append(('begin', name)) - _add_to_tag_cache(result, *entry) + _add_to_tag_cache(result, entry_folders, entry_files, music_path) result.append(('end', name)) result.append(('songList begin',)) @@ -273,7 +275,7 @@ def _add_to_tag_cache(result, folders, files): result.append(('songList end',)) -def tracks_to_directory_tree(tracks): +def tracks_to_directory_tree(tracks, music_path): directories = ({}, []) for track in tracks: @@ -282,8 +284,7 @@ def tracks_to_directory_tree(tracks): absolute_track_dir_path = os.path.dirname(uri_to_path(track.uri)) relative_track_dir_path = re.sub( - '^' + re.escape(settings.LOCAL_MUSIC_PATH), b'', - absolute_track_dir_path) + '^' + re.escape(music_path), b'', absolute_track_dir_path) for part in split_path(relative_track_dir_path): path = os.path.join(path, part) diff --git a/mopidy/scanner.py b/mopidy/scanner.py index 4b057774..8bc57349 100644 --- a/mopidy/scanner.py +++ b/mopidy/scanner.py @@ -42,6 +42,7 @@ from mopidy.utils import log, path, versioning def main(): options = parse_options() + config = {} # TODO Read config from new config system log.setup_root_logger() log.setup_console_logging(options.verbosity_level) @@ -67,7 +68,8 @@ def main(): logging.info('Done scanning; writing tag cache...') - for row in mpd_translator.tracks_to_tag_cache_format(tracks): + for row in mpd_translator.tracks_to_tag_cache_format( + tracks, config['mpd']['music_path']): if len(row) == 1: print ('%s' % row).encode('utf-8') else: diff --git a/tests/frontends/mpd/dispatcher_test.py b/tests/frontends/mpd/dispatcher_test.py index 3c32cd32..35e18c3b 100644 --- a/tests/frontends/mpd/dispatcher_test.py +++ b/tests/frontends/mpd/dispatcher_test.py @@ -13,9 +13,14 @@ from tests import unittest class MpdDispatcherTest(unittest.TestCase): def setUp(self): + config = { + 'mpd': { + 'password': None, + } + } self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() - self.dispatcher = MpdDispatcher() + self.dispatcher = MpdDispatcher(config=config) def tearDown(self): pykka.ActorRegistry.stop_all() diff --git a/tests/frontends/mpd/protocol/__init__.py b/tests/frontends/mpd/protocol/__init__.py index 9d24c3fa..e62141ee 100644 --- a/tests/frontends/mpd/protocol/__init__.py +++ b/tests/frontends/mpd/protocol/__init__.py @@ -23,12 +23,20 @@ class MockConnection(mock.Mock): class BaseTestCase(unittest.TestCase): + def get_config(self): + return { + 'mpd': { + 'password': None, + } + } + def setUp(self): self.backend = dummy.create_dummy_backend_proxy() self.core = core.Core.start(backends=[self.backend]).proxy() self.connection = MockConnection() - self.session = session.MpdSession(self.connection, core=self.core) + self.session = session.MpdSession( + self.connection, config=self.get_config(), core=self.core) self.dispatcher = self.session.dispatcher self.context = self.dispatcher.context diff --git a/tests/frontends/mpd/protocol/authentication_test.py b/tests/frontends/mpd/protocol/authentication_test.py index 26b03f45..2597ddef 100644 --- a/tests/frontends/mpd/protocol/authentication_test.py +++ b/tests/frontends/mpd/protocol/authentication_test.py @@ -1,63 +1,56 @@ from __future__ import unicode_literals -from mopidy import settings - from tests.frontends.mpd import protocol -class AuthenticationTest(protocol.BaseTestCase): - def test_authentication_with_valid_password_is_accepted(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' +class AuthenticationActiveTest(protocol.BaseTestCase): + def get_config(self): + config = super(AuthenticationActiveTest, self).get_config() + config['mpd']['password'] = 'topsecret' + return config + def test_authentication_with_valid_password_is_accepted(self): self.sendRequest('password "topsecret"') self.assertTrue(self.dispatcher.authenticated) self.assertInResponse('OK') def test_authentication_with_invalid_password_is_not_accepted(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('password "secret"') self.assertFalse(self.dispatcher.authenticated) self.assertEqualResponse('ACK [3@0] {password} incorrect password') - def test_authentication_with_anything_when_password_check_turned_off(self): - settings.MPD_SERVER_PASSWORD = None - - self.sendRequest('any request at all') - self.assertTrue(self.dispatcher.authenticated) - self.assertEqualResponse('ACK [5@0] {} unknown command "any"') - def test_anything_when_not_authenticated_should_fail(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('any request at all') self.assertFalse(self.dispatcher.authenticated) self.assertEqualResponse( u'ACK [4@0] {any} you don\'t have permission for "any"') def test_close_is_allowed_without_authentication(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('close') self.assertFalse(self.dispatcher.authenticated) def test_commands_is_allowed_without_authentication(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('commands') self.assertFalse(self.dispatcher.authenticated) self.assertInResponse('OK') def test_notcommands_is_allowed_without_authentication(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('notcommands') self.assertFalse(self.dispatcher.authenticated) self.assertInResponse('OK') def test_ping_is_allowed_without_authentication(self): - settings.MPD_SERVER_PASSWORD = u'topsecret' - self.sendRequest('ping') self.assertFalse(self.dispatcher.authenticated) self.assertInResponse('OK') + + +class AuthenticationInactiveTest(protocol.BaseTestCase): + def test_authentication_with_anything_when_password_check_turned_off(self): + self.sendRequest('any request at all') + self.assertTrue(self.dispatcher.authenticated) + self.assertEqualResponse('ACK [5@0] {} unknown command "any"') + + def test_any_password_is_not_accepted_when_password_check_turned_off(self): + self.sendRequest('password "secret"') + self.assertEqualResponse('ACK [3@0] {password} incorrect password') diff --git a/tests/frontends/mpd/protocol/connection_test.py b/tests/frontends/mpd/protocol/connection_test.py index 840ce48f..01deb7a7 100644 --- a/tests/frontends/mpd/protocol/connection_test.py +++ b/tests/frontends/mpd/protocol/connection_test.py @@ -2,8 +2,6 @@ from __future__ import unicode_literals from mock import patch -from mopidy import settings - from tests.frontends.mpd import protocol @@ -26,21 +24,6 @@ class ConnectionHandlerTest(protocol.BaseTestCase): self.assertEqualResponse( 'ACK [4@0] {kill} you don\'t have permission for "kill"') - def test_valid_password_is_accepted(self): - settings.MPD_SERVER_PASSWORD = 'topsecret' - self.sendRequest('password "topsecret"') - self.assertEqualResponse('OK') - - def test_invalid_password_is_not_accepted(self): - settings.MPD_SERVER_PASSWORD = 'topsecret' - self.sendRequest('password "secret"') - self.assertEqualResponse('ACK [3@0] {password} incorrect password') - - def test_any_password_is_not_accepted_when_password_check_turned_off(self): - settings.MPD_SERVER_PASSWORD = None - self.sendRequest('password "secret"') - self.assertEqualResponse('ACK [3@0] {password} incorrect password') - def test_ping(self): self.sendRequest('ping') self.assertEqualResponse('OK') diff --git a/tests/frontends/mpd/protocol/reflection_test.py b/tests/frontends/mpd/protocol/reflection_test.py index f2720473..16f4579f 100644 --- a/tests/frontends/mpd/protocol/reflection_test.py +++ b/tests/frontends/mpd/protocol/reflection_test.py @@ -1,7 +1,5 @@ from __future__ import unicode_literals -from mopidy import settings - from tests.frontends.mpd import protocol @@ -29,19 +27,6 @@ class ReflectionHandlerTest(protocol.BaseTestCase): self.assertNotInResponse('command: sticker') self.assertInResponse('OK') - def test_commands_show_less_if_auth_required_and_not_authed(self): - settings.MPD_SERVER_PASSWORD = u'secret' - self.sendRequest('commands') - # Not requiring auth - self.assertInResponse('command: close') - self.assertInResponse('command: commands') - self.assertInResponse('command: notcommands') - self.assertInResponse('command: password') - self.assertInResponse('command: ping') - # Requiring auth - self.assertNotInResponse('command: play') - self.assertNotInResponse('command: status') - def test_decoders(self): self.sendRequest('decoders') self.assertInResponse('OK') @@ -53,8 +38,35 @@ class ReflectionHandlerTest(protocol.BaseTestCase): self.assertInResponse('command: kill') self.assertInResponse('OK') + def test_tagtypes(self): + self.sendRequest('tagtypes') + self.assertInResponse('OK') + + def test_urlhandlers(self): + self.sendRequest('urlhandlers') + self.assertInResponse('OK') + self.assertInResponse('handler: dummy') + + +class ReflectionWhenNotAuthedTest(protocol.BaseTestCase): + def get_config(self): + config = super(ReflectionWhenNotAuthedTest, self).get_config() + config['mpd']['password'] = 'topsecret' + return config + + def test_commands_show_less_if_auth_required_and_not_authed(self): + self.sendRequest('commands') + # Not requiring auth + self.assertInResponse('command: close') + self.assertInResponse('command: commands') + self.assertInResponse('command: notcommands') + self.assertInResponse('command: password') + self.assertInResponse('command: ping') + # Requiring auth + self.assertNotInResponse('command: play') + self.assertNotInResponse('command: status') + def test_notcommands_returns_more_if_auth_required_and_not_authed(self): - settings.MPD_SERVER_PASSWORD = u'secret' self.sendRequest('notcommands') # Not requiring auth self.assertNotInResponse('command: close') @@ -65,12 +77,3 @@ class ReflectionHandlerTest(protocol.BaseTestCase): # Requiring auth self.assertInResponse('command: play') self.assertInResponse('command: status') - - def test_tagtypes(self): - self.sendRequest('tagtypes') - self.assertInResponse('OK') - - def test_urlhandlers(self): - self.sendRequest('urlhandlers') - self.assertInResponse('OK') - self.assertInResponse('handler: dummy') diff --git a/tests/frontends/mpd/translator_test.py b/tests/frontends/mpd/translator_test.py index 088ae137..5df65c5c 100644 --- a/tests/frontends/mpd/translator_test.py +++ b/tests/frontends/mpd/translator_test.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import datetime import os -from mopidy import settings from mopidy.utils.path import mtime, uri_to_path from mopidy.frontends.mpd import translator, protocol from mopidy.models import Album, Artist, TlTrack, Playlist, Track @@ -24,11 +23,10 @@ class TrackMpdFormatTest(unittest.TestCase): ) def setUp(self): - settings.LOCAL_MUSIC_PATH = '/dir/subdir' + self.music_path = '/dir/subdir' mtime.set_fake_time(1234567) def tearDown(self): - settings.runtime.clear() mtime.undo_fake() def test_track_to_mpd_format_for_empty_track(self): @@ -137,15 +135,14 @@ class QueryFromMpdListFormatTest(unittest.TestCase): class TracksToTagCacheFormatTest(unittest.TestCase): def setUp(self): - settings.LOCAL_MUSIC_PATH = '/dir/subdir' + self.music_path = '/dir/subdir' mtime.set_fake_time(1234567) def tearDown(self): - settings.runtime.clear() mtime.undo_fake() def translate(self, track): - base_path = settings.LOCAL_MUSIC_PATH.encode('utf-8') + base_path = self.music_path.encode('utf-8') result = dict(translator.track_to_mpd_format(track)) result['file'] = uri_to_path(result['file'])[len(base_path) + 1:] result['key'] = os.path.basename(result['file']) @@ -177,11 +174,11 @@ class TracksToTagCacheFormatTest(unittest.TestCase): self.fail("Couldn't find end %s in result" % directory) def test_empty_tag_cache_has_header(self): - result = translator.tracks_to_tag_cache_format([]) + result = translator.tracks_to_tag_cache_format([], self.music_path) result = self.consume_headers(result) def test_empty_tag_cache_has_song_list(self): - result = translator.tracks_to_tag_cache_format([]) + result = translator.tracks_to_tag_cache_format([], self.music_path) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) @@ -190,12 +187,12 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_has_header(self): track = Track(uri='file:///dir/subdir/song.mp3') - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) def test_tag_cache_has_song_list(self): track = Track(uri='file:///dir/subdir/song.mp3') - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) @@ -205,7 +202,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_has_formated_track(self): track = Track(uri='file:///dir/subdir/song.mp3') formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) @@ -216,7 +213,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_has_formated_track_with_key_and_mtime(self): track = Track(uri='file:///dir/subdir/song.mp3') formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) @@ -227,7 +224,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_suports_directories(self): track = Track(uri='file:///dir/subdir/folder/song.mp3') formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) folder, result = self.consume_directory(result) @@ -241,7 +238,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_diretory_header_is_right(self): track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) folder, result = self.consume_directory(result) @@ -253,7 +250,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): def test_tag_cache_suports_sub_directories(self): track = Track(uri='file:///dir/subdir/folder/sub/song.mp3') formated = self.translate(track) - result = translator.tracks_to_tag_cache_format([track]) + result = translator.tracks_to_tag_cache_format([track], self.music_path) result = self.consume_headers(result) @@ -281,7 +278,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): formated.extend(self.translate(tracks[0])) formated.extend(self.translate(tracks[1])) - result = translator.tracks_to_tag_cache_format(tracks) + result = translator.tracks_to_tag_cache_format(tracks, self.music_path) result = self.consume_headers(result) song_list, result = self.consume_song_list(result) @@ -299,7 +296,7 @@ class TracksToTagCacheFormatTest(unittest.TestCase): formated.append(self.translate(tracks[0])) formated.append(self.translate(tracks[1])) - result = translator.tracks_to_tag_cache_format(tracks) + result = translator.tracks_to_tag_cache_format(tracks, self.music_path) result = self.consume_headers(result) folder, result = self.consume_directory(result) @@ -315,13 +312,10 @@ class TracksToTagCacheFormatTest(unittest.TestCase): class TracksToDirectoryTreeTest(unittest.TestCase): def setUp(self): - settings.LOCAL_MUSIC_PATH = '/root/' - - def tearDown(self): - settings.runtime.clear() + self.music_path = '/root/' def test_no_tracks_gives_emtpy_tree(self): - tree = translator.tracks_to_directory_tree([]) + tree = translator.tracks_to_directory_tree([], self.music_path) self.assertEqual(tree, ({}, [])) def test_top_level_files(self): @@ -330,18 +324,18 @@ class TracksToDirectoryTreeTest(unittest.TestCase): Track(uri='file:///root/file2.mp3'), Track(uri='file:///root/file3.mp3'), ] - tree = translator.tracks_to_directory_tree(tracks) + tree = translator.tracks_to_directory_tree(tracks, self.music_path) self.assertEqual(tree, ({}, tracks)) def test_single_file_in_subdir(self): tracks = [Track(uri='file:///root/dir/file1.mp3')] - tree = translator.tracks_to_directory_tree(tracks) + tree = translator.tracks_to_directory_tree(tracks, self.music_path) expected = ({'dir': ({}, tracks)}, []) self.assertEqual(tree, expected) def test_single_file_in_sub_subdir(self): tracks = [Track(uri='file:///root/dir1/dir2/file1.mp3')] - tree = translator.tracks_to_directory_tree(tracks) + tree = translator.tracks_to_directory_tree(tracks, self.music_path) expected = ({'dir1': ({'dir1/dir2': ({}, tracks)}, [])}, []) self.assertEqual(tree, expected) @@ -353,7 +347,7 @@ class TracksToDirectoryTreeTest(unittest.TestCase): Track(uri='file:///root/dir2/file4.mp3'), Track(uri='file:///root/dir2/sub/file5.mp3'), ] - tree = translator.tracks_to_directory_tree(tracks) + tree = translator.tracks_to_directory_tree(tracks, self.music_path) expected = ( { 'dir1': ({}, [tracks[1], tracks[2]]),