mpd: Annotate exceptions with current command automatically (fixes #649)

This commit is contained in:
Stein Magnus Jodal 2014-01-18 00:34:41 +01:00
parent 06856851f7
commit 31abe0bc93
17 changed files with 69 additions and 64 deletions

View File

@ -165,7 +165,12 @@ class MpdDispatcher(object):
def _call_handler(self, request):
(handler, kwargs) = self._find_handler(request)
return handler(self.context, **kwargs)
try:
return handler(self.context, **kwargs)
except exceptions.MpdAckError as exc:
if exc.command is None:
exc.command = handler.__name__.split('__', 1)[0]
raise
def _find_handler(self, request):
for pattern in protocol.request_handlers:

View File

@ -21,7 +21,7 @@ class MpdAckError(MopidyException):
error_code = 0
def __init__(self, message='', index=0, command=''):
def __init__(self, message='', index=0, command=None):
super(MpdAckError, self).__init__(message, index, command)
self.message = message
self.index = index
@ -50,6 +50,7 @@ class MpdPermissionError(MpdAckError):
def __init__(self, *args, **kwargs):
super(MpdPermissionError, self).__init__(*args, **kwargs)
assert self.command is not None, 'command must be given explicitly'
self.message = 'you don\'t have permission for "%s"' % self.command
@ -58,12 +59,14 @@ class MpdUnknownCommand(MpdAckError):
def __init__(self, *args, **kwargs):
super(MpdUnknownCommand, self).__init__(*args, **kwargs)
assert self.command is not None, 'command must be given explicitly'
self.message = 'unknown command "%s"' % self.command
self.command = ''
class MpdNoCommand(MpdUnknownCommand):
def __init__(self, *args, **kwargs):
kwargs['command'] = ''
super(MpdNoCommand, self).__init__(*args, **kwargs)
self.message = 'No command given'

View File

@ -16,7 +16,7 @@ def disableoutput(context, outputid):
if int(outputid) == 0:
context.core.playback.set_mute(False)
else:
raise MpdNoExistError('No such audio output', command='disableoutput')
raise MpdNoExistError('No such audio output')
@handle_request(r'enableoutput\ "(?P<outputid>\d+)"$')
@ -31,7 +31,7 @@ def enableoutput(context, outputid):
if int(outputid) == 0:
context.core.playback.set_mute(True)
else:
raise MpdNoExistError('No such audio output', command='enableoutput')
raise MpdNoExistError('No such audio output')
@handle_request(r'outputs$')

View File

@ -30,7 +30,7 @@ def kill(context):
@handle_request(r'password\ "(?P<password>[^"]+)"$', auth_required=False)
def password_(context, password):
def password(context, password):
"""
*musicpd.org, connection section:*
@ -42,7 +42,7 @@ def password_(context, password):
if password == context.config['mpd']['password']:
context.dispatcher.authenticated = True
else:
raise MpdPasswordError('incorrect password', command='password')
raise MpdPasswordError('incorrect password')
@handle_request(r'ping$', auth_required=False)

View File

@ -44,7 +44,7 @@ def add(context, uri):
tracks.extend(future.get())
if not tracks:
raise MpdNoExistError('directory or file not found', command='add')
raise MpdNoExistError('directory or file not found')
context.core.tracklist.add(tracks=tracks)
@ -69,14 +69,14 @@ def addid(context, uri, songpos=None):
- ``addid ""`` should return an error.
"""
if not uri:
raise MpdNoExistError('No such song', command='addid')
raise MpdNoExistError('No such song')
if songpos is not None:
songpos = int(songpos)
if songpos and songpos > context.core.tracklist.length.get():
raise MpdArgError('Bad song index', command='addid')
raise MpdArgError('Bad song index')
tl_tracks = context.core.tracklist.add(uri=uri, at_position=songpos).get()
if not tl_tracks:
raise MpdNoExistError('No such song', command='addid')
raise MpdNoExistError('No such song')
return ('Id', tl_tracks[0].tlid)
@ -125,7 +125,7 @@ def deleteid(context, tlid):
tlid = int(tlid)
tl_tracks = context.core.tracklist.remove(tlid=[tlid]).get()
if not tl_tracks:
raise MpdNoExistError('No such song', command='deleteid')
raise MpdNoExistError('No such song')
@handle_request(r'clear$')
@ -181,7 +181,7 @@ def moveid(context, tlid, to):
to = int(to)
tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get()
if not tl_tracks:
raise MpdNoExistError('No such song', command='moveid')
raise MpdNoExistError('No such song')
position = context.core.tracklist.index(tl_tracks[0]).get()
context.core.tracklist.move(position, position + 1, to)
@ -239,7 +239,7 @@ def playlistid(context, tlid=None):
tlid = int(tlid)
tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get()
if not tl_tracks:
raise MpdNoExistError('No such song', command='playlistid')
raise MpdNoExistError('No such song')
position = context.core.tracklist.index(tl_tracks[0]).get()
return translator.track_to_mpd_format(tl_tracks[0], position=position)
else:
@ -276,7 +276,7 @@ def playlistinfo(context, songpos=None, start=None, end=None):
start = 0
start = int(start)
if not (0 <= start <= context.core.tracklist.length.get()):
raise MpdArgError('Bad song index', command='playlistinfo')
raise MpdArgError('Bad song index')
if end is not None:
end = int(end)
if end > context.core.tracklist.length.get():
@ -403,7 +403,7 @@ def swapid(context, tlid1, tlid2):
tl_tracks1 = context.core.tracklist.filter(tlid=[tlid1]).get()
tl_tracks2 = context.core.tracklist.filter(tlid=[tlid2]).get()
if not tl_tracks1 or not tl_tracks2:
raise MpdNoExistError('No such song', command='swapid')
raise MpdNoExistError('No such song')
position1 = context.core.tracklist.index(tl_tracks1[0]).get()
position2 = context.core.tracklist.index(tl_tracks2[0]).get()
swap(context, position1, position2)

View File

@ -7,4 +7,4 @@ from mopidy.mpd.exceptions import MpdNoCommand
@handle_request(r'[\ ]*$')
def empty(context):
"""The original MPD server returns an error on an empty request."""
raise MpdNoCommand
raise MpdNoCommand()

View File

@ -163,7 +163,7 @@ def count(context, mpd_query):
try:
query = _query_from_mpd_search_format(mpd_query)
except ValueError:
raise MpdArgError('incorrect arguments', command='count')
raise MpdArgError('incorrect arguments')
results = context.core.library.find_exact(**query).get()
result_tracks = _get_tracks(results)
return [
@ -433,7 +433,7 @@ def listall(context, uri=None):
result.append(('file', ref.uri))
if not result:
raise MpdNoExistError('Not found', command='listall')
raise MpdNoExistError('Not found')
return [('directory', uri)] + result
@ -474,7 +474,7 @@ def listallinfo(context, uri=None):
result.append(obj)
if not result:
raise MpdNoExistError('Not found', command='listallinfo')
raise MpdNoExistError('Not found')
return [('directory', uri)] + result

View File

@ -151,12 +151,12 @@ def playid(context, tlid):
return _play_minus_one(context)
tl_tracks = context.core.tracklist.filter(tlid=[tlid]).get()
if not tl_tracks:
raise MpdNoExistError('No such song', command='playid')
raise MpdNoExistError('No such song')
return context.core.playback.play(tl_tracks[0]).get()
@handle_request(r'play\ ("?)(?P<songpos>-?\d+)\1$')
def playpos(context, songpos):
def play__pos(context, songpos):
"""
*musicpd.org, playback section:*
@ -184,7 +184,7 @@ def playpos(context, songpos):
tl_track = context.core.tracklist.slice(songpos, songpos + 1).get()[0]
return context.core.playback.play(tl_track).get()
except IndexError:
raise MpdArgError('Bad song index', command='play')
raise MpdArgError('Bad song index')
def _play_minus_one(context):
@ -325,7 +325,7 @@ def seek(context, songpos, seconds):
"""
tl_track = context.core.playback.current_tl_track.get()
if context.core.tracklist.index(tl_track).get() != int(songpos):
playpos(context, songpos)
play__pos(context, songpos)
context.core.playback.seek(int(seconds) * 1000).get()

View File

@ -7,7 +7,7 @@ from mopidy.mpd.exceptions import MpdNotImplemented
@handle_request(
r'sticker\ delete\ "(?P<field>[^"]+)"\ '
r'"(?P<uri>[^"]+)"(\ "(?P<name>[^"]+)")*$')
def sticker_delete(context, field, uri, name=None):
def sticker__delete(context, field, uri, name=None):
"""
*musicpd.org, sticker section:*
@ -22,7 +22,7 @@ def sticker_delete(context, field, uri, name=None):
@handle_request(
r'sticker\ find\ "(?P<field>[^"]+)"\ "(?P<uri>[^"]+)"\ '
r'"(?P<name>[^"]+)"$')
def sticker_find(context, field, uri, name):
def sticker__find(context, field, uri, name):
"""
*musicpd.org, sticker section:*
@ -38,7 +38,7 @@ def sticker_find(context, field, uri, name):
@handle_request(
r'sticker\ get\ "(?P<field>[^"]+)"\ "(?P<uri>[^"]+)"\ '
r'"(?P<name>[^"]+)"$')
def sticker_get(context, field, uri, name):
def sticker__get(context, field, uri, name):
"""
*musicpd.org, sticker section:*
@ -50,7 +50,7 @@ def sticker_get(context, field, uri, name):
@handle_request(r'sticker\ list\ "(?P<field>[^"]+)"\ "(?P<uri>[^"]+)"$')
def sticker_list(context, field, uri):
def sticker__list(context, field, uri):
"""
*musicpd.org, sticker section:*
@ -64,7 +64,7 @@ def sticker_list(context, field, uri):
@handle_request(
r'sticker\ set\ "(?P<field>[^"]+)"\ "(?P<uri>[^"]+)"\ '
r'"(?P<name>[^"]+)"\ "(?P<value>[^"]+)"$')
def sticker_set(context, field, uri, name, value):
def sticker__set(context, field, uri, name, value):
"""
*musicpd.org, sticker section:*

View File

@ -24,7 +24,7 @@ def listplaylist(context, name):
"""
playlist = context.lookup_playlist_from_name(name)
if not playlist:
raise MpdNoExistError('No such playlist', command='listplaylist')
raise MpdNoExistError('No such playlist')
return ['file: %s' % t.uri for t in playlist.tracks]
@ -44,7 +44,7 @@ def listplaylistinfo(context, name):
"""
playlist = context.lookup_playlist_from_name(name)
if not playlist:
raise MpdNoExistError('No such playlist', command='listplaylistinfo')
raise MpdNoExistError('No such playlist')
return playlist_to_mpd_format(playlist)
@ -115,7 +115,7 @@ def load(context, name, start=None, end=None):
"""
playlist = context.lookup_playlist_from_name(name)
if not playlist:
raise MpdNoExistError('No such playlist', command='load')
raise MpdNoExistError('No such playlist')
if start is not None:
start = int(start)
if end is not None:

View File

@ -6,20 +6,20 @@ from tests.mpd import protocol
class ChannelsHandlerTest(protocol.BaseTestCase):
def test_subscribe(self):
self.sendRequest('subscribe "topic"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {subscribe} Not implemented')
def test_unsubscribe(self):
self.sendRequest('unsubscribe "topic"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {unsubscribe} Not implemented')
def test_channels(self):
self.sendRequest('channels')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {channels} Not implemented')
def test_readmessages(self):
self.sendRequest('readmessages')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {readmessages} Not implemented')
def test_sendmessage(self):
self.sendRequest('sendmessage "topic" "a message"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sendmessage} Not implemented')

View File

@ -253,7 +253,7 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
def test_playlistfind(self):
self.sendRequest('playlistfind "tag" "needle"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistfind} Not implemented')
def test_playlistfind_by_filename_not_in_tracklist(self):
self.sendRequest('playlistfind "filename" "file:///dev/null"')
@ -391,11 +391,11 @@ class CurrentPlaylistHandlerTest(protocol.BaseTestCase):
def test_playlistsearch(self):
self.sendRequest('playlistsearch "any" "needle"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistsearch} Not implemented')
def test_playlistsearch_without_quotes(self):
self.sendRequest('playlistsearch any "needle"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistsearch} Not implemented')
def test_plchanges_with_lower_version_returns_changes(self):
self.core.tracklist.add(

View File

@ -36,7 +36,7 @@ class PlaybackOptionsHandlerTest(protocol.BaseTestCase):
def test_crossfade(self):
self.sendRequest('crossfade "10"')
self.assertInResponse('ACK [0@0] {} Not implemented')
self.assertInResponse('ACK [0@0] {crossfade} Not implemented')
def test_random_off(self):
self.sendRequest('random "0"')
@ -135,15 +135,15 @@ class PlaybackOptionsHandlerTest(protocol.BaseTestCase):
def test_replay_gain_mode_off(self):
self.sendRequest('replay_gain_mode "off"')
self.assertInResponse('ACK [0@0] {} Not implemented')
self.assertInResponse('ACK [0@0] {replay_gain_mode} Not implemented')
def test_replay_gain_mode_track(self):
self.sendRequest('replay_gain_mode "track"')
self.assertInResponse('ACK [0@0] {} Not implemented')
self.assertInResponse('ACK [0@0] {replay_gain_mode} Not implemented')
def test_replay_gain_mode_album(self):
self.sendRequest('replay_gain_mode "album"')
self.assertInResponse('ACK [0@0] {} Not implemented')
self.assertInResponse('ACK [0@0] {replay_gain_mode} Not implemented')
def test_replay_gain_status_default(self):
self.sendRequest('replay_gain_status')

View File

@ -8,7 +8,7 @@ from tests.mpd import protocol
class StatusHandlerTest(protocol.BaseTestCase):
def test_clearerror(self):
self.sendRequest('clearerror')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {clearerror} Not implemented')
def test_currentsong(self):
track = Track()

View File

@ -7,29 +7,29 @@ class StickersHandlerTest(protocol.BaseTestCase):
def test_sticker_get(self):
self.sendRequest(
'sticker get "song" "file:///dev/urandom" "a_name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')
def test_sticker_set(self):
self.sendRequest(
'sticker set "song" "file:///dev/urandom" "a_name" "a_value"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')
def test_sticker_delete_with_name(self):
self.sendRequest(
'sticker delete "song" "file:///dev/urandom" "a_name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')
def test_sticker_delete_without_name(self):
self.sendRequest(
'sticker delete "song" "file:///dev/urandom"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')
def test_sticker_list(self):
self.sendRequest(
'sticker list "song" "file:///dev/urandom"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')
def test_sticker_find(self):
self.sendRequest(
'sticker find "song" "file:///dev/urandom" "a_name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {sticker} Not implemented')

View File

@ -189,28 +189,28 @@ class PlaylistsHandlerTest(protocol.BaseTestCase):
def test_playlistadd(self):
self.sendRequest('playlistadd "name" "dummy:a"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistadd} Not implemented')
def test_playlistclear(self):
self.sendRequest('playlistclear "name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistclear} Not implemented')
def test_playlistdelete(self):
self.sendRequest('playlistdelete "name" "5"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistdelete} Not implemented')
def test_playlistmove(self):
self.sendRequest('playlistmove "name" "5" "10"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {playlistmove} Not implemented')
def test_rename(self):
self.sendRequest('rename "old_name" "new_name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {rename} Not implemented')
def test_rm(self):
self.sendRequest('rm "name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {rm} Not implemented')
def test_save(self):
self.sendRequest('save "name"')
self.assertEqualResponse('ACK [0@0] {} Not implemented')
self.assertEqualResponse('ACK [0@0] {save} Not implemented')

View File

@ -25,7 +25,7 @@ class MpdExceptionsTest(unittest.TestCase):
def test_get_mpd_ack_with_default_values(self):
e = MpdAckError('A description')
self.assertEqual(e.get_mpd_ack(), 'ACK [0@0] {} A description')
self.assertEqual(e.get_mpd_ack(), 'ACK [0@0] {None} A description')
def test_get_mpd_ack_with_values(self):
try:
@ -38,24 +38,21 @@ class MpdExceptionsTest(unittest.TestCase):
raise MpdUnknownCommand(command='play')
except MpdAckError as e:
self.assertEqual(
e.get_mpd_ack(),
'ACK [5@0] {} unknown command "play"')
e.get_mpd_ack(), 'ACK [5@0] {} unknown command "play"')
def test_mpd_no_command(self):
try:
raise MpdNoCommand
except MpdAckError as e:
self.assertEqual(
e.get_mpd_ack(),
'ACK [5@0] {} No command given')
e.get_mpd_ack(), 'ACK [5@0] {} No command given')
def test_mpd_system_error(self):
try:
raise MpdSystemError('foo')
except MpdSystemError as e:
self.assertEqual(
e.get_mpd_ack(),
'ACK [52@0] {} foo')
e.get_mpd_ack(), 'ACK [52@0] {None} foo')
def test_mpd_permission_error(self):
try: