From 666800ec57ac3ffb75a680b31d37bed35ef2176a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 16 Oct 2012 14:00:34 +0200 Subject: [PATCH] Fix most flake8 warnings (#211) --- mopidy/__init__.py | 9 ++- mopidy/__main__.py | 40 +++++++------ mopidy/audio/__init__.py | 39 +++++++------ mopidy/audio/mixers/__init__.py | 3 +- mopidy/audio/mixers/auto.py | 9 +-- mopidy/audio/mixers/fake.py | 14 ++--- mopidy/audio/mixers/nad.py | 25 ++++---- mopidy/backends/base/stored_playlists.py | 2 +- mopidy/backends/local/__init__.py | 19 ++++--- mopidy/backends/local/translator.py | 9 ++- mopidy/backends/spotify/__init__.py | 5 +- mopidy/backends/spotify/container_manager.py | 7 ++- mopidy/backends/spotify/library.py | 9 +-- mopidy/backends/spotify/playlist_manager.py | 33 +++++++---- mopidy/backends/spotify/session_manager.py | 12 ++-- mopidy/backends/spotify/stored_playlists.py | 13 +++-- mopidy/backends/spotify/translator.py | 3 +- mopidy/core/current_playlist.py | 7 +-- mopidy/core/playback.py | 29 +++++----- mopidy/core/stored_playlists.py | 6 +- mopidy/frontends/mpd/__init__.py | 23 +++++--- mopidy/frontends/mpd/dispatcher.py | 37 ++++++------ mopidy/frontends/mpd/exceptions.py | 8 +++ mopidy/frontends/mpd/protocol/__init__.py | 1 + mopidy/frontends/mpd/protocol/audio_output.py | 7 ++- mopidy/frontends/mpd/protocol/command_list.py | 3 + mopidy/frontends/mpd/protocol/connection.py | 8 ++- .../mpd/protocol/current_playlist.py | 49 ++++++++++------ mopidy/frontends/mpd/protocol/empty.py | 1 + mopidy/frontends/mpd/protocol/music_db.py | 55 +++++++++++------- mopidy/frontends/mpd/protocol/playback.py | 32 ++++++++--- mopidy/frontends/mpd/protocol/reflection.py | 32 +++++++---- mopidy/frontends/mpd/protocol/status.py | 57 +++++++++++++------ mopidy/frontends/mpd/protocol/stickers.py | 27 ++++++--- .../mpd/protocol/stored_playlists.py | 32 +++++++---- mopidy/frontends/mpd/translator.py | 20 +++++-- mopidy/frontends/mpris/__init__.py | 6 +- mopidy/frontends/mpris/objects.py | 47 +++++++-------- mopidy/models.py | 9 +-- mopidy/scanner.py | 10 ++-- mopidy/utils/__init__.py | 1 - mopidy/utils/deps.py | 10 ++-- mopidy/utils/log.py | 5 ++ mopidy/utils/network.py | 32 +++++++---- mopidy/utils/path.py | 7 ++- mopidy/utils/process.py | 10 +++- mopidy/utils/settings.py | 29 ++++++---- 47 files changed, 531 insertions(+), 320 deletions(-) diff --git a/mopidy/__init__.py b/mopidy/__init__.py index 3b0f76a5..2a88666c 100644 --- a/mopidy/__init__.py +++ b/mopidy/__init__.py @@ -20,12 +20,14 @@ CACHE_PATH = os.path.join(str(glib.get_user_cache_dir()), 'mopidy') SETTINGS_PATH = os.path.join(str(glib.get_user_config_dir()), 'mopidy') SETTINGS_FILE = os.path.join(SETTINGS_PATH, 'settings.py') + def get_version(): try: return get_git_version() except EnvironmentError: return __version__ + def get_git_version(): process = Popen(['git', 'describe'], stdout=PIPE, stderr=PIPE) if process.wait() != 0: @@ -35,14 +37,17 @@ def get_git_version(): version = version[1:] return version + def get_platform(): return platform.platform() + def get_python(): implementation = platform.python_implementation() version = platform.python_version() return u' '.join([implementation, version]) + class MopidyException(Exception): def __init__(self, message, *args, **kwargs): super(MopidyException, self).__init__(message, *args, **kwargs) @@ -53,13 +58,15 @@ class MopidyException(Exception): """Reimplement message field that was deprecated in Python 2.6""" return self._message - @message.setter + @message.setter # noqa def message(self, message): self._message = message + class SettingsError(MopidyException): pass + class OptionalDependencyError(MopidyException): pass diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 3e586044..bfc600f5 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -24,8 +24,8 @@ sys.argv[1:] = gstreamer_args # Add ../ to the path so we can run Mopidy from a Git checkout without # installing it on the system. -sys.path.insert(0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) +sys.path.insert( + 0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) import mopidy @@ -46,10 +46,10 @@ def main(): log.setup_logging(options.verbosity_level, options.save_debug_log) check_old_folders() setup_settings(options.interactive) - audio = setup_audio() - backend = setup_backend(audio) - core = setup_core(audio, backend) - setup_frontends(core) + audio_ref = setup_audio() + backend_ref = setup_backend(audio_ref) + core_ref = setup_core(audio_ref, backend_ref) + setup_frontends(core_ref) loop.run() except mopidy.SettingsError as ex: logger.error(ex.message) @@ -68,25 +68,32 @@ def main(): def parse_options(): parser = optparse.OptionParser(version=u'Mopidy %s' % mopidy.get_version()) - parser.add_option('--help-gst', + parser.add_option( + '--help-gst', action='store_true', dest='help_gst', help='show GStreamer help options') - parser.add_option('-i', '--interactive', + parser.add_option( + '-i', '--interactive', action='store_true', dest='interactive', help='ask interactively for required settings which are missing') - parser.add_option('-q', '--quiet', + parser.add_option( + '-q', '--quiet', action='store_const', const=0, dest='verbosity_level', help='less output (warning level)') - parser.add_option('-v', '--verbose', + parser.add_option( + '-v', '--verbose', action='count', default=1, dest='verbosity_level', help='more output (debug level)') - parser.add_option('--save-debug-log', + parser.add_option( + '--save-debug-log', action='store_true', dest='save_debug_log', help='save debug log to "./mopidy.log"') - parser.add_option('--list-settings', + parser.add_option( + '--list-settings', action='callback', callback=list_settings_optparse_callback, help='list current settings') - parser.add_option('--list-deps', + parser.add_option( + '--list-deps', action='callback', callback=list_deps_optparse_callback, help='list dependencies and their versions') return parser.parse_args(args=mopidy_args)[0] @@ -98,9 +105,10 @@ def check_old_folders(): if not os.path.isdir(old_settings_folder): return - logger.warning(u'Old settings folder found at %s, settings.py should be ' - 'moved to %s, any cache data should be deleted. See release notes ' - 'for further instructions.', old_settings_folder, mopidy.SETTINGS_PATH) + logger.warning( + u'Old settings folder found at %s, settings.py should be moved ' + u'to %s, any cache data should be deleted. See release notes for ' + u'further instructions.', old_settings_folder, mopidy.SETTINGS_PATH) def setup_settings(interactive): diff --git a/mopidy/audio/__init__.py b/mopidy/audio/__init__.py index 10a74959..a342799b 100644 --- a/mopidy/audio/__init__.py +++ b/mopidy/audio/__init__.py @@ -70,8 +70,8 @@ class Audio(ThreadingActor): self._playbin.set_property('audio-sink', output) logger.info('Output set to %s', settings.OUTPUT) except gobject.GError as ex: - logger.error('Failed to create output "%s": %s', - settings.OUTPUT, ex) + logger.error( + 'Failed to create output "%s": %s', settings.OUTPUT, ex) process.exit_process() def _setup_mixer(self): @@ -85,11 +85,11 @@ class Audio(ThreadingActor): return try: - mixerbin = gst.parse_bin_from_description(settings.MIXER, - ghost_unconnected_pads=False) + mixerbin = gst.parse_bin_from_description( + settings.MIXER, ghost_unconnected_pads=False) except gobject.GError as ex: - logger.warning('Failed to create mixer "%s": %s', - settings.MIXER, ex) + logger.warning( + 'Failed to create mixer "%s": %s', settings.MIXER, ex) return # We assume that the bin will contain a single mixer. @@ -215,10 +215,11 @@ class Audio(ThreadingActor): :type volume: int :rtype: :class:`True` if successful, else :class:`False` """ - self._playbin.get_state() # block until state changes are done - handeled = self._playbin.seek_simple(gst.Format(gst.FORMAT_TIME), - gst.SEEK_FLAG_FLUSH, position * gst.MSECOND) - self._playbin.get_state() # block until seek is done + self._playbin.get_state() # block until state changes are done + handeled = self._playbin.seek_simple( + gst.Format(gst.FORMAT_TIME), gst.SEEK_FLAG_FLUSH, + position * gst.MSECOND) + self._playbin.get_state() # block until seek is done return handeled def start_playback(self): @@ -279,16 +280,16 @@ class Audio(ThreadingActor): """ result = self._playbin.set_state(state) if result == gst.STATE_CHANGE_FAILURE: - logger.warning('Setting GStreamer state to %s: failed', - state.value_name) + logger.warning( + 'Setting GStreamer state to %s: failed', state.value_name) return False elif result == gst.STATE_CHANGE_ASYNC: - logger.debug('Setting GStreamer state to %s: async', - state.value_name) + logger.debug( + 'Setting GStreamer state to %s: async', state.value_name) return True else: - logger.debug('Setting GStreamer state to %s: OK', - state.value_name) + logger.debug( + 'Setting GStreamer state to %s: OK', state.value_name) return True def get_volume(self): @@ -316,7 +317,8 @@ class Audio(ThreadingActor): avg_volume = float(sum(volumes)) / len(volumes) new_scale = (0, 100) - old_scale = (self._mixer_track.min_volume, self._mixer_track.max_volume) + old_scale = ( + self._mixer_track.min_volume, self._mixer_track.max_volume) return utils.rescale(avg_volume, old=old_scale, new=new_scale) def set_volume(self, volume): @@ -335,7 +337,8 @@ class Audio(ThreadingActor): return False old_scale = (0, 100) - new_scale = (self._mixer_track.min_volume, self._mixer_track.max_volume) + new_scale = ( + self._mixer_track.min_volume, self._mixer_track.max_volume) volume = utils.rescale(volume, old=old_scale, new=new_scale) diff --git a/mopidy/audio/mixers/__init__.py b/mopidy/audio/mixers/__init__.py index a0247519..08ecda0d 100644 --- a/mopidy/audio/mixers/__init__.py +++ b/mopidy/audio/mixers/__init__.py @@ -5,7 +5,8 @@ import gobject def create_track(label, initial_volume, min_volume, max_volume, - num_channels, flags): + num_channels, flags): + class Track(gst.interfaces.MixerTrack): def __init__(self): super(Track, self).__init__() diff --git a/mopidy/audio/mixers/auto.py b/mopidy/audio/mixers/auto.py index 1233afa3..3dce11f7 100644 --- a/mopidy/audio/mixers/auto.py +++ b/mopidy/audio/mixers/auto.py @@ -10,10 +10,11 @@ logger = logging.getLogger('mopidy.audio.mixers.auto') # TODO: we might want to add some ranking to the mixers we know about? class AutoAudioMixer(gst.Bin): - __gstdetails__ = ('AutoAudioMixer', - 'Mixer', - 'Element automatically selects a mixer.', - 'Thomas Adamcik') + __gstdetails__ = ( + 'AutoAudioMixer', + 'Mixer', + 'Element automatically selects a mixer.', + 'Thomas Adamcik') def __init__(self): gst.Bin.__init__(self) diff --git a/mopidy/audio/mixers/fake.py b/mopidy/audio/mixers/fake.py index c5faa03f..d44fbd71 100644 --- a/mopidy/audio/mixers/fake.py +++ b/mopidy/audio/mixers/fake.py @@ -7,19 +7,19 @@ from mopidy.audio.mixers import create_track class FakeMixer(gst.Element, gst.ImplementsInterface, gst.interfaces.Mixer): - __gstdetails__ = ('FakeMixer', - 'Mixer', - 'Fake mixer for use in tests.', - 'Thomas Adamcik') + __gstdetails__ = ( + 'FakeMixer', + 'Mixer', + 'Fake mixer for use in tests.', + 'Thomas Adamcik') track_label = gobject.property(type=str, default='Master') track_initial_volume = gobject.property(type=int, default=0) track_min_volume = gobject.property(type=int, default=0) track_max_volume = gobject.property(type=int, default=100) track_num_channels = gobject.property(type=int, default=2) - track_flags = gobject.property(type=int, - default=(gst.interfaces.MIXER_TRACK_MASTER | - gst.interfaces.MIXER_TRACK_OUTPUT)) + track_flags = gobject.property(type=int, default=( + gst.interfaces.MIXER_TRACK_MASTER | gst.interfaces.MIXER_TRACK_OUTPUT)) def __init__(self): gst.Element.__init__(self) diff --git a/mopidy/audio/mixers/nad.py b/mopidy/audio/mixers/nad.py index 667dee53..d50c1242 100644 --- a/mopidy/audio/mixers/nad.py +++ b/mopidy/audio/mixers/nad.py @@ -8,7 +8,7 @@ import gst try: import serial except ImportError: - serial = None + serial = None # noqa from pykka.actor import ThreadingActor @@ -19,10 +19,11 @@ logger = logging.getLogger('mopidy.audio.mixers.nad') class NadMixer(gst.Element, gst.ImplementsInterface, gst.interfaces.Mixer): - __gstdetails__ = ('NadMixer', - 'Mixer', - 'Mixer to control NAD amplifiers using a serial link', - 'Stein Magnus Jodal') + __gstdetails__ = ( + 'NadMixer', + 'Mixer', + 'Mixer to control NAD amplifiers using a serial link', + 'Stein Magnus Jodal') port = gobject.property(type=str, default='/dev/ttyUSB0') source = gobject.property(type=str) @@ -41,8 +42,9 @@ class NadMixer(gst.Element, gst.ImplementsInterface, gst.interfaces.Mixer): min_volume=0, max_volume=100, num_channels=1, - flags=(gst.interfaces.MIXER_TRACK_MASTER | - gst.interfaces.MIXER_TRACK_OUTPUT)) + flags=( + gst.interfaces.MIXER_TRACK_MASTER | + gst.interfaces.MIXER_TRACK_OUTPUT)) return [track] def get_volume(self, track): @@ -121,8 +123,7 @@ class NadTalker(ThreadingActor): self._set_device_to_known_state() def _open_connection(self): - logger.info(u'NAD amplifier: Connecting through "%s"', - self.port) + logger.info(u'NAD amplifier: Connecting through "%s"', self.port) self._device = serial.Serial( port=self.port, baudrate=self.BAUDRATE, @@ -200,11 +201,13 @@ class NadTalker(ThreadingActor): for attempt in range(1, 4): if self._ask_device(key) == value: return - logger.info(u'NAD amplifier: Setting "%s" to "%s" (attempt %d/3)', + logger.info( + u'NAD amplifier: Setting "%s" to "%s" (attempt %d/3)', key, value, attempt) self._command_device(key, value) if self._ask_device(key) != value: - logger.info(u'NAD amplifier: Gave up on setting "%s" to "%s"', + logger.info( + u'NAD amplifier: Gave up on setting "%s" to "%s"', key, value) def _ask_device(self, key): diff --git a/mopidy/backends/base/stored_playlists.py b/mopidy/backends/base/stored_playlists.py index d1d52c9a..d808798d 100644 --- a/mopidy/backends/base/stored_playlists.py +++ b/mopidy/backends/base/stored_playlists.py @@ -22,7 +22,7 @@ class BaseStoredPlaylistsProvider(object): """ return copy(self._playlists) - @playlists.setter + @playlists.setter # noqa def playlists(self, playlists): self._playlists = playlists diff --git a/mopidy/backends/local/__init__.py b/mopidy/backends/local/__init__.py index ee8448b3..b34c3da5 100644 --- a/mopidy/backends/local/__init__.py +++ b/mopidy/backends/local/__init__.py @@ -1,5 +1,4 @@ import glob -import glib import logging import os import shutil @@ -8,7 +7,7 @@ from pykka.actor import ThreadingActor from mopidy import settings from mopidy.backends import base -from mopidy.models import Playlist, Track, Album +from mopidy.models import Playlist, Album from .translator import parse_m3u, parse_mpd_tag_cache @@ -45,7 +44,7 @@ class LocalStoredPlaylistsProvider(base.BaseStoredPlaylistsProvider): self.refresh() def lookup(self, uri): - pass # TODO + pass # TODO def refresh(self): playlists = [] @@ -118,11 +117,12 @@ class LocalLibraryProvider(base.BaseLibraryProvider): self.refresh() def refresh(self, uri=None): - tracks = parse_mpd_tag_cache(settings.LOCAL_TAG_CACHE_FILE, - settings.LOCAL_MUSIC_PATH) + tracks = parse_mpd_tag_cache( + settings.LOCAL_TAG_CACHE_FILE, settings.LOCAL_MUSIC_PATH) - logger.info('Loading tracks in %s from %s', settings.LOCAL_MUSIC_PATH, - settings.LOCAL_TAG_CACHE_FILE) + logger.info( + 'Loading tracks in %s from %s', + settings.LOCAL_MUSIC_PATH, settings.LOCAL_TAG_CACHE_FILE) for track in tracks: self._uri_mapping[track.uri] = track @@ -150,7 +150,8 @@ class LocalLibraryProvider(base.BaseLibraryProvider): artist_filter = lambda t: filter( lambda a: q == a.name, t.artists) uri_filter = lambda t: q == t.uri - any_filter = lambda t: (track_filter(t) or album_filter(t) or + any_filter = lambda t: ( + track_filter(t) or album_filter(t) or artist_filter(t) or uri_filter(t)) if field == 'track': @@ -178,7 +179,7 @@ class LocalLibraryProvider(base.BaseLibraryProvider): for value in values: q = value.strip().lower() - track_filter = lambda t: q in t.name.lower() + track_filter = lambda t: q in t.name.lower() album_filter = lambda t: q in getattr( t, 'album', Album()).name.lower() artist_filter = lambda t: filter( diff --git a/mopidy/backends/local/translator.py b/mopidy/backends/local/translator.py index 1fea555c..fbdace15 100644 --- a/mopidy/backends/local/translator.py +++ b/mopidy/backends/local/translator.py @@ -1,5 +1,4 @@ import logging -import os logger = logging.getLogger('mopidy.backends.local.translator') @@ -7,6 +6,7 @@ from mopidy.models import Track, Artist, Album from mopidy.utils import locale_decode from mopidy.utils.path import path_to_uri + def parse_m3u(file_path, music_folder): """ Convert M3U file list of uris @@ -51,6 +51,7 @@ def parse_m3u(file_path, music_folder): return uris + def parse_mpd_tag_cache(tag_cache, music_dir=''): """ Converts a MPD tag_cache into a lists of tracks, artists and albums. @@ -89,6 +90,7 @@ def parse_mpd_tag_cache(tag_cache, music_dir=''): return tracks + def _convert_mpd_data(data, tracks, music_dir): if not data: return @@ -128,7 +130,8 @@ def _convert_mpd_data(data, tracks, music_dir): artist_kwargs['musicbrainz_id'] = data['musicbrainz_artistid'] if 'musicbrainz_albumartistid' in data: - albumartist_kwargs['musicbrainz_id'] = data['musicbrainz_albumartistid'] + albumartist_kwargs['musicbrainz_id'] = ( + data['musicbrainz_albumartistid']) if data['file'][0] == '/': path = data['file'][1:] @@ -142,7 +145,7 @@ def _convert_mpd_data(data, tracks, music_dir): if albumartist_kwargs: albumartist = Artist(**albumartist_kwargs) album_kwargs['artists'] = [albumartist] - + if album_kwargs: album = Album(**album_kwargs) track_kwargs['album'] = album diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py index 0e2a2bfa..749a43c0 100644 --- a/mopidy/backends/spotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -9,6 +9,7 @@ logger = logging.getLogger('mopidy.backends.spotify') BITRATES = {96: 2, 160: 0, 320: 1} + class SpotifyBackend(ThreadingActor, base.Backend): """ A backend for playing music from the `Spotify `_ @@ -57,8 +58,8 @@ class SpotifyBackend(ThreadingActor, base.Backend): username = settings.SPOTIFY_USERNAME password = settings.SPOTIFY_PASSWORD - self.spotify = SpotifySessionManager(username, password, - audio=audio, backend_ref=self.actor_ref) + self.spotify = SpotifySessionManager( + username, password, audio=audio, backend_ref=self.actor_ref) def on_start(self): logger.info(u'Mopidy uses SPOTIFY(R) CORE') diff --git a/mopidy/backends/spotify/container_manager.py b/mopidy/backends/spotify/container_manager.py index 27a4d78a..a45b1adc 100644 --- a/mopidy/backends/spotify/container_manager.py +++ b/mopidy/backends/spotify/container_manager.py @@ -5,6 +5,7 @@ from spotify.manager import SpotifyContainerManager as \ logger = logging.getLogger('mopidy.backends.spotify.container_manager') + class SpotifyContainerManager(PyspotifyContainerManager): def __init__(self, session_manager): PyspotifyContainerManager.__init__(self) @@ -25,13 +26,13 @@ class SpotifyContainerManager(PyspotifyContainerManager): def playlist_added(self, container, playlist, position, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: playlist added at position %d', - position) + logger.debug( + u'Callback called: playlist added at position %d', position) # container_loaded() is called after this callback, so we do not need # to handle this callback. def playlist_moved(self, container, playlist, old_position, new_position, - userdata): + userdata): """Callback used by pyspotify""" logger.debug( u'Callback called: playlist "%s" moved from position %d to %d', diff --git a/mopidy/backends/spotify/library.py b/mopidy/backends/spotify/library.py index 18276ecd..8519a650 100644 --- a/mopidy/backends/spotify/library.py +++ b/mopidy/backends/spotify/library.py @@ -22,7 +22,8 @@ class SpotifyTrack(Track): if self._track: return self._track elif self._spotify_track.is_loaded(): - self._track = SpotifyTranslator.to_mopidy_track(self._spotify_track) + self._track = SpotifyTranslator.to_mopidy_track( + self._spotify_track) return self._track else: return self._unloaded_track @@ -59,7 +60,7 @@ class SpotifyLibraryProvider(BaseLibraryProvider): return None def refresh(self, uri=None): - pass # TODO + pass # TODO def search(self, **query): if not query: @@ -81,7 +82,7 @@ class SpotifyLibraryProvider(BaseLibraryProvider): if field == u'any': spotify_query.append(value) elif field == u'year': - value = int(value.split('-')[0]) # Extract year + value = int(value.split('-')[0]) # Extract year spotify_query.append(u'%s:%d' % (field, value)) else: spotify_query.append(u'%s:"%s"' % (field, value)) @@ -90,6 +91,6 @@ class SpotifyLibraryProvider(BaseLibraryProvider): queue = Queue.Queue() self.backend.spotify.search(spotify_query, queue) try: - return queue.get(timeout=3) # XXX What is an reasonable timeout? + return queue.get(timeout=3) # XXX What is an reasonable timeout? except Queue.Empty: return Playlist(tracks=[]) diff --git a/mopidy/backends/spotify/playlist_manager.py b/mopidy/backends/spotify/playlist_manager.py index 05f9514d..e1308a49 100644 --- a/mopidy/backends/spotify/playlist_manager.py +++ b/mopidy/backends/spotify/playlist_manager.py @@ -5,6 +5,7 @@ from spotify.manager import SpotifyPlaylistManager as PyspotifyPlaylistManager logger = logging.getLogger('mopidy.backends.spotify.playlist_manager') + class SpotifyPlaylistManager(PyspotifyPlaylistManager): def __init__(self, session_manager): PyspotifyPlaylistManager.__init__(self) @@ -12,48 +13,55 @@ class SpotifyPlaylistManager(PyspotifyPlaylistManager): def tracks_added(self, playlist, tracks, position, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: ' + logger.debug( + u'Callback called: ' u'%d track(s) added to position %d in playlist "%s"', len(tracks), position, playlist.name()) self.session_manager.refresh_stored_playlists() def tracks_moved(self, playlist, tracks, new_position, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: ' + logger.debug( + u'Callback called: ' u'%d track(s) moved to position %d in playlist "%s"', len(tracks), new_position, playlist.name()) self.session_manager.refresh_stored_playlists() def tracks_removed(self, playlist, tracks, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: ' + logger.debug( + u'Callback called: ' u'%d track(s) removed from playlist "%s"', len(tracks), playlist.name()) self.session_manager.refresh_stored_playlists() def playlist_renamed(self, playlist, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: Playlist renamed to "%s"', - playlist.name()) + logger.debug( + u'Callback called: Playlist renamed to "%s"', playlist.name()) self.session_manager.refresh_stored_playlists() def playlist_state_changed(self, playlist, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: The state of playlist "%s" changed', + logger.debug( + u'Callback called: The state of playlist "%s" changed', playlist.name()) def playlist_update_in_progress(self, playlist, done, userdata): """Callback used by pyspotify""" if done: - logger.debug(u'Callback called: ' - u'Update of playlist "%s" done', playlist.name()) + logger.debug( + u'Callback called: Update of playlist "%s" done', + playlist.name()) else: - logger.debug(u'Callback called: ' - u'Update of playlist "%s" in progress', playlist.name()) + logger.debug( + u'Callback called: Update of playlist "%s" in progress', + playlist.name()) def playlist_metadata_updated(self, playlist, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: Metadata updated for playlist "%s"', + logger.debug( + u'Callback called: Metadata updated for playlist "%s"', playlist.name()) def track_created_changed(self, playlist, position, user, when, userdata): @@ -90,5 +98,6 @@ class SpotifyPlaylistManager(PyspotifyPlaylistManager): def image_changed(self, playlist, image, userdata): """Callback used by pyspotify""" - logger.debug(u'Callback called: Image changed for playlist "%s"', + logger.debug( + u'Callback called: Image changed for playlist "%s"', playlist.name()) diff --git a/mopidy/backends/spotify/session_manager.py b/mopidy/backends/spotify/session_manager.py index dab759c9..99859abd 100644 --- a/mopidy/backends/spotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -53,7 +53,8 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): logger.info(u'Connected to Spotify') self.session = session - logger.debug(u'Preferred Spotify bitrate is %s kbps', + logger.debug( + u'Preferred Spotify bitrate is %s kbps', settings.SPOTIFY_BITRATE) self.session.set_preferred_bitrate(BITRATES[settings.SPOTIFY_BITRATE]) @@ -85,7 +86,7 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): logger.debug(u'User message: %s', message.strip()) def music_delivery(self, session, frames, frame_size, num_frames, - sample_type, sample_rate, channels): + sample_type, sample_rate, channels): """Callback used by pyspotify""" # pylint: disable = R0913 # Too many arguments (8/5) @@ -136,7 +137,8 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): if not self._initial_data_receive_completed: logger.debug(u'Still getting data; skipped refresh of playlists') return - playlists = map(SpotifyTranslator.to_mopidy_playlist, + playlists = map( + SpotifyTranslator.to_mopidy_playlist, self.session.playlist_container()) playlists = filter(None, playlists) self.backend.stored_playlists.playlists = playlists @@ -153,8 +155,8 @@ class SpotifySessionManager(BaseThread, PyspotifySessionManager): for t in results.tracks()]) queue.put(playlist) self.connected.wait() - self.session.search(query, callback, track_count=100, - album_count=0, artist_count=0) + self.session.search( + query, callback, track_count=100, album_count=0, artist_count=0) def logout(self): """Log out from spotify""" diff --git a/mopidy/backends/spotify/stored_playlists.py b/mopidy/backends/spotify/stored_playlists.py index 054e2bd1..85695c40 100644 --- a/mopidy/backends/spotify/stored_playlists.py +++ b/mopidy/backends/spotify/stored_playlists.py @@ -1,20 +1,21 @@ from mopidy.backends.base import BaseStoredPlaylistsProvider + class SpotifyStoredPlaylistsProvider(BaseStoredPlaylistsProvider): def create(self, name): - pass # TODO + pass # TODO def delete(self, playlist): - pass # TODO + pass # TODO def lookup(self, uri): - pass # TODO + pass # TODO def refresh(self): - pass # TODO + pass # TODO def rename(self, playlist, new_name): - pass # TODO + pass # TODO def save(self, playlist): - pass # TODO + pass # TODO diff --git a/mopidy/backends/spotify/translator.py b/mopidy/backends/spotify/translator.py index 1a8f048d..82c11ef7 100644 --- a/mopidy/backends/spotify/translator.py +++ b/mopidy/backends/spotify/translator.py @@ -7,6 +7,7 @@ from mopidy.models import Artist, Album, Track, Playlist logger = logging.getLogger('mopidy.backends.spotify.translator') + class SpotifyTranslator(object): @classmethod def to_mopidy_artist(cls, spotify_artist): @@ -57,7 +58,7 @@ class SpotifyTranslator(object): name=spotify_playlist.name(), # FIXME if check on link is a hackish workaround for is_local tracks=[cls.to_mopidy_track(t) for t in spotify_playlist - if str(Link.from_track(t, 0))], + if str(Link.from_track(t, 0))], ) except SpotifyError, e: logger.warning(u'Failed translating Spotify playlist: %s', e) diff --git a/mopidy/core/current_playlist.py b/mopidy/core/current_playlist.py index 17cd70ad..5aa7ed5d 100644 --- a/mopidy/core/current_playlist.py +++ b/mopidy/core/current_playlist.py @@ -6,7 +6,6 @@ from mopidy.models import CpTrack from . import listener - logger = logging.getLogger('mopidy.core') @@ -57,7 +56,7 @@ class CurrentPlaylistController(object): """ return self._version - @version.setter + @version.setter # noqa def version(self, version): self._version = version self.core.playback.on_current_playlist_change() @@ -128,8 +127,8 @@ class CurrentPlaylistController(object): if key == 'cpid': matches = filter(lambda ct: ct.cpid == value, matches) else: - matches = filter(lambda ct: getattr(ct.track, key) == value, - matches) + matches = filter( + lambda ct: getattr(ct.track, key) == value, matches) if len(matches) == 1: return matches[0] criteria_string = ', '.join( diff --git a/mopidy/core/playback.py b/mopidy/core/playback.py index f3592831..90e7e639 100644 --- a/mopidy/core/playback.py +++ b/mopidy/core/playback.py @@ -283,7 +283,7 @@ class PlaybackController(object): """ return self._state - @state.setter + @state.setter # noqa def state(self, new_state): (old_state, self._state) = (self.state, new_state) logger.debug(u'Changing state: %s -> %s', old_state, new_state) @@ -304,7 +304,7 @@ class PlaybackController(object): # For testing return self._volume - @volume.setter + @volume.setter # noqa def volume(self, volume): if self.audio: self.audio.set_volume(volume) @@ -488,36 +488,37 @@ class PlaybackController(object): logger.debug(u'Triggering track playback paused event') if self.current_track is None: return - listener.CoreListener.send('track_playback_paused', - track=self.current_track, - time_position=self.time_position) + listener.CoreListener.send( + 'track_playback_paused', + track=self.current_track, time_position=self.time_position) def _trigger_track_playback_resumed(self): logger.debug(u'Triggering track playback resumed event') if self.current_track is None: return - listener.CoreListener.send('track_playback_resumed', - track=self.current_track, - time_position=self.time_position) + listener.CoreListener.send( + 'track_playback_resumed', + track=self.current_track, time_position=self.time_position) def _trigger_track_playback_started(self): logger.debug(u'Triggering track playback started event') if self.current_track is None: return - listener.CoreListener.send('track_playback_started', - track=self.current_track) + listener.CoreListener.send( + 'track_playback_started', track=self.current_track) def _trigger_track_playback_ended(self): logger.debug(u'Triggering track playback ended event') if self.current_track is None: return - listener.CoreListener.send('track_playback_ended', - track=self.current_track, - time_position=self.time_position) + listener.CoreListener.send( + 'track_playback_ended', + track=self.current_track, time_position=self.time_position) def _trigger_playback_state_changed(self, old_state, new_state): logger.debug(u'Triggering playback state change event') - listener.CoreListener.send('playback_state_changed', + listener.CoreListener.send( + 'playback_state_changed', old_state=old_state, new_state=new_state) def _trigger_options_changed(self): diff --git a/mopidy/core/stored_playlists.py b/mopidy/core/stored_playlists.py index 6ea9b1d3..2c5ef752 100644 --- a/mopidy/core/stored_playlists.py +++ b/mopidy/core/stored_playlists.py @@ -21,7 +21,7 @@ class StoredPlaylistsController(object): """ return self.backend.stored_playlists.playlists.get() - @playlists.setter + @playlists.setter # noqa def playlists(self, playlists): self.backend.stored_playlists.playlists = playlists @@ -71,8 +71,8 @@ class StoredPlaylistsController(object): if len(matches) == 0: raise LookupError('"%s" match no playlists' % criteria_string) else: - raise LookupError('"%s" match multiple playlists' - % criteria_string) + raise LookupError( + '"%s" match multiple playlists' % criteria_string) def lookup(self, uri): """ diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py index d7eeaaa3..e5bafcf1 100644 --- a/mopidy/frontends/mpd/__init__.py +++ b/mopidy/frontends/mpd/__init__.py @@ -7,7 +7,6 @@ from mopidy import core, settings from mopidy.frontends.mpd import dispatcher, protocol from mopidy.utils import locale_decode, log, network, process - logger = logging.getLogger('mopidy.frontends.mpd') @@ -32,11 +31,13 @@ class MpdFrontend(actor.ThreadingActor, core.CoreListener): port = settings.MPD_SERVER_PORT try: - network.Server(hostname, port, + network.Server( + hostname, port, protocol=MpdSession, protocol_kwargs={'core': core}, max_connections=settings.MPD_SERVER_MAX_CONNECTIONS) except IOError as error: - logger.error(u'MPD server startup failed: %s', locale_decode(error)) + logger.error( + u'MPD server startup failed: %s', locale_decode(error)) sys.exit(1) logger.info(u'MPD server running at [%s]:%s', hostname, port) @@ -86,15 +87,18 @@ class MpdSession(network.LineProtocol): self.send_lines([u'OK MPD %s' % protocol.VERSION]) def on_line_received(self, line): - logger.debug(u'Request from [%s]:%s to %s: %s', self.host, self.port, - self.actor_urn, line) + logger.debug( + u'Request from [%s]:%s to %s: %s', + self.host, self.port, self.actor_urn, line) response = self.dispatcher.handle_request(line) if not response: return - logger.debug(u'Response to [%s]:%s from %s: %s', self.host, self.port, - self.actor_urn, log.indent(self.terminator.join(response))) + logger.debug( + u'Response to [%s]:%s from %s: %s', + self.host, self.port, self.actor_urn, + log.indent(self.terminator.join(response))) self.send_lines(response) @@ -105,8 +109,9 @@ class MpdSession(network.LineProtocol): try: return super(MpdSession, self).decode(line.decode('string_escape')) except ValueError: - logger.warning(u'Stopping actor due to unescaping error, data ' - 'supplied by client was not valid.') + logger.warning( + u'Stopping actor due to unescaping error, data ' + u'supplied by client was not valid.') self.stop() def close(self): diff --git a/mopidy/frontends/mpd/dispatcher.py b/mopidy/frontends/mpd/dispatcher.py index c29cdf4d..24db6a7a 100644 --- a/mopidy/frontends/mpd/dispatcher.py +++ b/mopidy/frontends/mpd/dispatcher.py @@ -2,22 +2,22 @@ import logging import re from pykka import ActorDeadError -from pykka.registry import ActorRegistry -from mopidy import core, settings +from mopidy import settings from mopidy.frontends.mpd import exceptions from mopidy.frontends.mpd.protocol import mpd_commands, request_handlers # Do not remove the following import. The protocol modules must be imported to # get them registered as request handlers. # pylint: disable = W0611 -from mopidy.frontends.mpd.protocol import (audio_output, command_list, - connection, current_playlist, empty, music_db, playback, reflection, - status, stickers, stored_playlists) +from mopidy.frontends.mpd.protocol import ( + audio_output, command_list, connection, current_playlist, empty, music_db, + playback, reflection, status, stickers, stored_playlists) # pylint: enable = W0611 from mopidy.utils import flatten logger = logging.getLogger('mopidy.frontends.mpd.dispatcher') + class MpdDispatcher(object): """ The MPD session feeds the MPD dispatcher with requests. The dispatcher @@ -71,7 +71,6 @@ class MpdDispatcher(object): else: return response - ### Filter: catch MPD ACK errors def _catch_mpd_ack_errors_filter(self, request, response, filter_chain): @@ -82,7 +81,6 @@ class MpdDispatcher(object): mpd_ack_error.index = self.command_list_index return [mpd_ack_error.get_mpd_ack()] - ### Filter: authenticate def _authenticate_filter(self, request, response, filter_chain): @@ -101,7 +99,6 @@ class MpdDispatcher(object): else: raise exceptions.MpdPermissionError(command=command_name) - ### Filter: command list def _command_list_filter(self, request, response, filter_chain): @@ -117,25 +114,27 @@ class MpdDispatcher(object): return response def _is_receiving_command_list(self, request): - return (self.command_list is not False - and request != u'command_list_end') + return ( + self.command_list is not False and + request != u'command_list_end') def _is_processing_command_list(self, request): - return (self.command_list_index is not None - and request != u'command_list_end') - + return ( + self.command_list_index is not None and + request != u'command_list_end') ### Filter: idle def _idle_filter(self, request, response, filter_chain): if self._is_currently_idle() and not self._noidle.match(request): - logger.debug(u'Client sent us %s, only %s is allowed while in ' - 'the idle state', repr(request), repr(u'noidle')) + logger.debug( + u'Client sent us %s, only %s is allowed while in ' + u'the idle state', repr(request), repr(u'noidle')) self.context.session.close() return [] if not self._is_currently_idle() and self._noidle.match(request): - return [] # noidle was called before idle + return [] # noidle was called before idle response = self._call_next_filter(request, response, filter_chain) @@ -147,7 +146,6 @@ class MpdDispatcher(object): def _is_currently_idle(self): return bool(self.context.subscriptions) - ### Filter: add OK def _add_ok_filter(self, request, response, filter_chain): @@ -159,7 +157,6 @@ class MpdDispatcher(object): def _has_error(self, response): return response and response[-1].startswith(u'ACK') - ### Filter: call handler def _call_handler_filter(self, request, response, filter_chain): @@ -181,8 +178,8 @@ class MpdDispatcher(object): return (request_handlers[pattern], matches.groupdict()) command_name = request.split(' ')[0] if command_name in [command.name for command in mpd_commands]: - raise exceptions.MpdArgError(u'incorrect arguments', - command=command_name) + raise exceptions.MpdArgError( + u'incorrect arguments', command=command_name) raise exceptions.MpdUnknownCommand(command=command_name) def _format_response(self, response): diff --git a/mopidy/frontends/mpd/exceptions.py b/mopidy/frontends/mpd/exceptions.py index 661d6905..e5844b60 100644 --- a/mopidy/frontends/mpd/exceptions.py +++ b/mopidy/frontends/mpd/exceptions.py @@ -1,5 +1,6 @@ from mopidy import MopidyException + class MpdAckError(MopidyException): """See fields on this class for available MPD error codes""" @@ -33,12 +34,15 @@ class MpdAckError(MopidyException): return u'ACK [%i@%i] {%s} %s' % ( self.__class__.error_code, self.index, self.command, self.message) + class MpdArgError(MpdAckError): error_code = MpdAckError.ACK_ERROR_ARG + class MpdPasswordError(MpdAckError): error_code = MpdAckError.ACK_ERROR_PASSWORD + class MpdPermissionError(MpdAckError): error_code = MpdAckError.ACK_ERROR_PERMISSION @@ -46,6 +50,7 @@ class MpdPermissionError(MpdAckError): super(MpdPermissionError, self).__init__(*args, **kwargs) self.message = u'you don\'t have permission for "%s"' % self.command + class MpdUnknownCommand(MpdAckError): error_code = MpdAckError.ACK_ERROR_UNKNOWN @@ -54,12 +59,15 @@ class MpdUnknownCommand(MpdAckError): self.message = u'unknown command "%s"' % self.command self.command = u'' + class MpdNoExistError(MpdAckError): error_code = MpdAckError.ACK_ERROR_NO_EXIST + class MpdSystemError(MpdAckError): error_code = MpdAckError.ACK_ERROR_SYSTEM + class MpdNotImplemented(MpdAckError): error_code = 0 diff --git a/mopidy/frontends/mpd/protocol/__init__.py b/mopidy/frontends/mpd/protocol/__init__.py index f0b56a57..590a8ef4 100644 --- a/mopidy/frontends/mpd/protocol/__init__.py +++ b/mopidy/frontends/mpd/protocol/__init__.py @@ -29,6 +29,7 @@ mpd_commands = set() request_handlers = {} + def handle_request(pattern, auth_required=True): """ Decorator for connecting command handlers to command requests. diff --git a/mopidy/frontends/mpd/protocol/audio_output.py b/mopidy/frontends/mpd/protocol/audio_output.py index 7147963a..7e50c8c0 100644 --- a/mopidy/frontends/mpd/protocol/audio_output.py +++ b/mopidy/frontends/mpd/protocol/audio_output.py @@ -1,6 +1,7 @@ from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.exceptions import MpdNotImplemented + @handle_request(r'^disableoutput "(?P\d+)"$') def disableoutput(context, outputid): """ @@ -10,7 +11,8 @@ def disableoutput(context, outputid): Turns an output off. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^enableoutput "(?P\d+)"$') def enableoutput(context, outputid): @@ -21,7 +23,8 @@ def enableoutput(context, outputid): Turns an output on. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^outputs$') def outputs(context): diff --git a/mopidy/frontends/mpd/protocol/command_list.py b/mopidy/frontends/mpd/protocol/command_list.py index 37e5c93d..a58c11e2 100644 --- a/mopidy/frontends/mpd/protocol/command_list.py +++ b/mopidy/frontends/mpd/protocol/command_list.py @@ -1,6 +1,7 @@ from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.exceptions import MpdUnknownCommand + @handle_request(r'^command_list_begin$') def command_list_begin(context): """ @@ -21,6 +22,7 @@ def command_list_begin(context): context.dispatcher.command_list = [] context.dispatcher.command_list_ok = False + @handle_request(r'^command_list_end$') def command_list_end(context): """See :meth:`command_list_begin()`.""" @@ -43,6 +45,7 @@ def command_list_end(context): command_list_response.append(u'list_OK') return command_list_response + @handle_request(r'^command_list_ok_begin$') def command_list_ok_begin(context): """See :meth:`command_list_begin()`.""" diff --git a/mopidy/frontends/mpd/protocol/connection.py b/mopidy/frontends/mpd/protocol/connection.py index ff230173..3228807f 100644 --- a/mopidy/frontends/mpd/protocol/connection.py +++ b/mopidy/frontends/mpd/protocol/connection.py @@ -1,7 +1,8 @@ from mopidy import settings from mopidy.frontends.mpd.protocol import handle_request -from mopidy.frontends.mpd.exceptions import (MpdPasswordError, - MpdPermissionError) +from mopidy.frontends.mpd.exceptions import ( + MpdPasswordError, MpdPermissionError) + @handle_request(r'^close$', auth_required=False) def close(context): @@ -14,6 +15,7 @@ def close(context): """ context.session.close() + @handle_request(r'^kill$') def kill(context): """ @@ -25,6 +27,7 @@ def kill(context): """ raise MpdPermissionError(command=u'kill') + @handle_request(r'^password "(?P[^"]+)"$', auth_required=False) def password_(context, password): """ @@ -40,6 +43,7 @@ def password_(context, password): else: raise MpdPasswordError(u'incorrect password', command=u'password') + @handle_request(r'^ping$', auth_required=False) def ping(context): """ diff --git a/mopidy/frontends/mpd/protocol/current_playlist.py b/mopidy/frontends/mpd/protocol/current_playlist.py index 622f79c9..429af2cc 100644 --- a/mopidy/frontends/mpd/protocol/current_playlist.py +++ b/mopidy/frontends/mpd/protocol/current_playlist.py @@ -1,8 +1,8 @@ -from mopidy.frontends.mpd.exceptions import (MpdArgError, MpdNoExistError, - MpdNotImplemented) +from mopidy.frontends.mpd import translator +from mopidy.frontends.mpd.exceptions import ( + MpdArgError, MpdNoExistError, MpdNotImplemented) from mopidy.frontends.mpd.protocol import handle_request -from mopidy.frontends.mpd.translator import (track_to_mpd_format, - tracks_to_mpd_format) + @handle_request(r'^add "(?P[^"]*)"$') def add(context, uri): @@ -29,6 +29,7 @@ def add(context, uri): raise MpdNoExistError( u'directory or file not found', command=u'add') + @handle_request(r'^addid "(?P[^"]*)"( "(?P\d+)")*$') def addid(context, uri, songpos=None): """ @@ -57,10 +58,11 @@ def addid(context, uri, songpos=None): raise MpdNoExistError(u'No such song', command=u'addid') if songpos and songpos > context.core.current_playlist.length.get(): raise MpdArgError(u'Bad song index', command=u'addid') - cp_track = context.core.current_playlist.add(track, - at_position=songpos).get() + cp_track = context.core.current_playlist.add( + track, at_position=songpos).get() return ('Id', cp_track.cpid) + @handle_request(r'^delete "(?P\d+):(?P\d+)*"$') def delete_range(context, start, end=None): """ @@ -81,6 +83,7 @@ def delete_range(context, start, end=None): for (cpid, _) in cp_tracks: context.core.current_playlist.remove(cpid=cpid) + @handle_request(r'^delete "(?P\d+)"$') def delete_songpos(context, songpos): """See :meth:`delete_range`""" @@ -92,6 +95,7 @@ def delete_songpos(context, songpos): except IndexError: raise MpdArgError(u'Bad song index', command=u'delete') + @handle_request(r'^deleteid "(?P\d+)"$') def deleteid(context, cpid): """ @@ -109,6 +113,7 @@ def deleteid(context, cpid): except LookupError: raise MpdNoExistError(u'No such song', command=u'deleteid') + @handle_request(r'^clear$') def clear(context): """ @@ -120,6 +125,7 @@ def clear(context): """ context.core.current_playlist.clear() + @handle_request(r'^move "(?P\d+):(?P\d+)*" "(?P\d+)"$') def move_range(context, start, to, end=None): """ @@ -137,6 +143,7 @@ def move_range(context, start, to, end=None): to = int(to) context.core.current_playlist.move(start, end, to) + @handle_request(r'^move "(?P\d+)" "(?P\d+)"$') def move_songpos(context, songpos, to): """See :meth:`move_range`.""" @@ -144,6 +151,7 @@ def move_songpos(context, songpos, to): to = int(to) context.core.current_playlist.move(songpos, songpos + 1, to) + @handle_request(r'^moveid "(?P\d+)" "(?P\d+)"$') def moveid(context, cpid, to): """ @@ -161,6 +169,7 @@ def moveid(context, cpid, to): position = context.core.current_playlist.index(cp_track).get() context.core.current_playlist.move(position, position + 1, to) + @handle_request(r'^playlist$') def playlist(context): """ @@ -176,6 +185,7 @@ def playlist(context): """ return playlistinfo(context) + @handle_request(r'^playlistfind (?P[^"]+) "(?P[^"]+)"$') @handle_request(r'^playlistfind "(?P[^"]+)" "(?P[^"]+)"$') def playlistfind(context, tag, needle): @@ -194,10 +204,11 @@ def playlistfind(context, tag, needle): try: cp_track = context.core.current_playlist.get(uri=needle).get() position = context.core.current_playlist.index(cp_track).get() - return track_to_mpd_format(cp_track, position=position) + return translator.track_to_mpd_format(cp_track, position=position) except LookupError: return None - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^playlistid( "(?P\d+)")*$') def playlistid(context, cpid=None): @@ -214,19 +225,19 @@ def playlistid(context, cpid=None): cpid = int(cpid) cp_track = context.core.current_playlist.get(cpid=cpid).get() position = context.core.current_playlist.index(cp_track).get() - return track_to_mpd_format(cp_track, position=position) + return translator.track_to_mpd_format(cp_track, position=position) except LookupError: raise MpdNoExistError(u'No such song', command=u'playlistid') else: - return tracks_to_mpd_format( + return translator.tracks_to_mpd_format( context.core.current_playlist.cp_tracks.get()) + @handle_request(r'^playlistinfo$') @handle_request(r'^playlistinfo "-1"$') @handle_request(r'^playlistinfo "(?P-?\d+)"$') @handle_request(r'^playlistinfo "(?P\d+):(?P\d+)*"$') -def playlistinfo(context, songpos=None, - start=None, end=None): +def playlistinfo(context, songpos=None, start=None, end=None): """ *musicpd.org, current playlist section:* @@ -244,7 +255,7 @@ def playlistinfo(context, songpos=None, if songpos is not None: songpos = int(songpos) cp_track = context.core.current_playlist.cp_tracks.get()[songpos] - return track_to_mpd_format(cp_track, position=songpos) + return translator.track_to_mpd_format(cp_track, position=songpos) else: if start is None: start = 0 @@ -256,7 +267,8 @@ def playlistinfo(context, songpos=None, if end > context.core.current_playlist.length.get(): end = None cp_tracks = context.core.current_playlist.cp_tracks.get() - return tracks_to_mpd_format(cp_tracks, start, end) + return translator.tracks_to_mpd_format(cp_tracks, start, end) + @handle_request(r'^playlistsearch "(?P[^"]+)" "(?P[^"]+)"$') @handle_request(r'^playlistsearch (?P\S+) "(?P[^"]+)"$') @@ -274,7 +286,8 @@ def playlistsearch(context, tag, needle): - does not add quotes around the tag - uses ``filename`` and ``any`` as tags """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^plchanges (?P-?\d+)$') @handle_request(r'^plchanges "(?P-?\d+)"$') @@ -295,9 +308,10 @@ def plchanges(context, version): """ # XXX Naive implementation that returns all tracks as changed if int(version) < context.core.current_playlist.version: - return tracks_to_mpd_format( + return translator.tracks_to_mpd_format( context.core.current_playlist.cp_tracks.get()) + @handle_request(r'^plchangesposid "(?P\d+)"$') def plchangesposid(context, version): """ @@ -321,6 +335,7 @@ def plchangesposid(context, version): result.append((u'Id', cpid)) return result + @handle_request(r'^shuffle$') @handle_request(r'^shuffle "(?P\d+):(?P\d+)*"$') def shuffle(context, start=None, end=None): @@ -338,6 +353,7 @@ def shuffle(context, start=None, end=None): end = int(end) context.core.current_playlist.shuffle(start, end) + @handle_request(r'^swap "(?P\d+)" "(?P\d+)"$') def swap(context, songpos1, songpos2): """ @@ -359,6 +375,7 @@ def swap(context, songpos1, songpos2): context.core.current_playlist.clear() context.core.current_playlist.append(tracks) + @handle_request(r'^swapid "(?P\d+)" "(?P\d+)"$') def swapid(context, cpid1, cpid2): """ diff --git a/mopidy/frontends/mpd/protocol/empty.py b/mopidy/frontends/mpd/protocol/empty.py index 4cdafd87..f2ee4757 100644 --- a/mopidy/frontends/mpd/protocol/empty.py +++ b/mopidy/frontends/mpd/protocol/empty.py @@ -1,5 +1,6 @@ from mopidy.frontends.mpd.protocol import handle_request + @handle_request(r'^[ ]*$') def empty(context): """The original MPD server returns ``OK`` on an empty request.""" diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index 2678714a..a5d5b214 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -5,6 +5,7 @@ from mopidy.frontends.mpd.exceptions import MpdArgError, MpdNotImplemented from mopidy.frontends.mpd.protocol import handle_request, stored_playlists from mopidy.frontends.mpd.translator import playlist_to_mpd_format + def _build_query(mpd_query): """ Parses a MPD query string and converts it to the Mopidy query format. @@ -21,7 +22,7 @@ def _build_query(mpd_query): field = m.groupdict()['field'].lower() if field == u'title': field = u'track' - field = str(field) # Needed for kwargs keys on OS X and Windows + field = str(field) # Needed for kwargs keys on OS X and Windows what = m.groupdict()['what'].lower() if field in query: query[field].append(what) @@ -29,6 +30,7 @@ def _build_query(mpd_query): query[field] = [what] return query + @handle_request(r'^count "(?P[^"]+)" "(?P[^"]*)"$') def count(context, tag, needle): """ @@ -39,11 +41,12 @@ def count(context, tag, needle): Counts the number of songs and their total playtime in the db matching ``TAG`` exactly. """ - return [('songs', 0), ('playtime', 0)] # TODO + return [('songs', 0), ('playtime', 0)] # TODO -@handle_request(r'^find ' - r'(?P("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ilename|' - r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$') + +@handle_request( + r'^find (?P("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ilename|' + r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$') def find(context, mpd_query): """ *musicpd.org, music database section:* @@ -72,9 +75,11 @@ def find(context, mpd_query): return playlist_to_mpd_format( context.core.library.find_exact(**query).get()) -@handle_request(r'^findadd ' - r'(?P("?([Aa]lbum|[Aa]rtist|[Ff]ilename|[Tt]itle|[Aa]ny)"? ' - '"[^"]+"\s?)+)$') + +@handle_request( + r'^findadd ' + r'(?P("?([Aa]lbum|[Aa]rtist|[Ff]ilename|[Tt]itle|[Aa]ny)"? ' + r'"[^"]+"\s?)+)$') def findadd(context, query): """ *musicpd.org, music database section:* @@ -88,8 +93,10 @@ def findadd(context, query): # TODO Add result to current playlist #result = context.find(query) -@handle_request(r'^list "?(?P([Aa]rtist|[Aa]lbum|[Dd]ate|[Gg]enre))"?' - '( (?P.*))?$') + +@handle_request( + r'^list "?(?P([Aa]rtist|[Aa]lbum|[Dd]ate|[Gg]enre))"?' + r'( (?P.*))?$') def list_(context, field, mpd_query=None): """ *musicpd.org, music database section:* @@ -183,7 +190,8 @@ def list_(context, field, mpd_query=None): elif field == u'date': return _list_date(context, query) elif field == u'genre': - pass # TODO We don't have genre in our internal data structures yet + pass # TODO We don't have genre in our internal data structures yet + def _list_build_query(field, mpd_query): """Converts a ``list`` query to a Mopidy query.""" @@ -208,7 +216,7 @@ def _list_build_query(field, mpd_query): query = {} while tokens: key = tokens[0].lower() - key = str(key) # Needed for kwargs keys on OS X and Windows + key = str(key) # Needed for kwargs keys on OS X and Windows value = tokens[1] tokens = tokens[2:] if key not in (u'artist', u'album', u'date', u'genre'): @@ -221,6 +229,7 @@ def _list_build_query(field, mpd_query): else: raise MpdArgError(u'not able to parse args', command=u'list') + def _list_artist(context, query): artists = set() playlist = context.core.library.find_exact(**query).get() @@ -229,6 +238,7 @@ def _list_artist(context, query): artists.add((u'Artist', artist.name)) return artists + def _list_album(context, query): albums = set() playlist = context.core.library.find_exact(**query).get() @@ -237,6 +247,7 @@ def _list_album(context, query): albums.add((u'Album', track.album.name)) return albums + def _list_date(context, query): dates = set() playlist = context.core.library.find_exact(**query).get() @@ -245,6 +256,7 @@ def _list_date(context, query): dates.add((u'Date', track.date)) return dates + @handle_request(r'^listall "(?P[^"]+)"') def listall(context, uri): """ @@ -254,7 +266,8 @@ def listall(context, uri): Lists all songs and directories in ``URI``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^listallinfo "(?P[^"]+)"') def listallinfo(context, uri): @@ -266,7 +279,8 @@ def listallinfo(context, uri): Same as ``listall``, except it also returns metadata info in the same format as ``lsinfo``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^lsinfo$') @handle_request(r'^lsinfo "(?P[^"]*)"$') @@ -288,7 +302,8 @@ def lsinfo(context, uri=None): """ if uri is None or uri == u'/' or uri == u'': return stored_playlists.listplaylists(context) - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^rescan( "(?P[^"]+)")*$') def rescan(context, uri=None): @@ -301,9 +316,10 @@ def rescan(context, uri=None): """ return update(context, uri, rescan_unmodified_files=True) -@handle_request(r'^search ' - r'(?P("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ilename|' - r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$') + +@handle_request( + r'^search (?P("?([Aa]lbum|[Aa]rtist|[Dd]ate|[Ff]ilename|' + r'[Tt]itle|[Aa]ny)"? "[^"]+"\s?)+)$') def search(context, mpd_query): """ *musicpd.org, music database section:* @@ -335,6 +351,7 @@ def search(context, mpd_query): return playlist_to_mpd_format( context.core.library.search(**query).get()) + @handle_request(r'^update( "(?P[^"]+)")*$') def update(context, uri=None, rescan_unmodified_files=False): """ @@ -352,4 +369,4 @@ def update(context, uri=None, rescan_unmodified_files=False): identifying the update job. You can read the current job id in the ``status`` response. """ - return {'updating_db': 0} # TODO + return {'updating_db': 0} # TODO diff --git a/mopidy/frontends/mpd/protocol/playback.py b/mopidy/frontends/mpd/protocol/playback.py index 76cefdc3..7851ebe0 100644 --- a/mopidy/frontends/mpd/protocol/playback.py +++ b/mopidy/frontends/mpd/protocol/playback.py @@ -1,7 +1,8 @@ from mopidy.core import PlaybackState from mopidy.frontends.mpd.protocol import handle_request -from mopidy.frontends.mpd.exceptions import (MpdArgError, MpdNoExistError, - MpdNotImplemented) +from mopidy.frontends.mpd.exceptions import ( + MpdArgError, MpdNoExistError, MpdNotImplemented) + @handle_request(r'^consume (?P[01])$') @handle_request(r'^consume "(?P[01])"$') @@ -20,6 +21,7 @@ def consume(context, state): else: context.core.playback.consume = False + @handle_request(r'^crossfade "(?P\d+)"$') def crossfade(context, seconds): """ @@ -30,7 +32,8 @@ def crossfade(context, seconds): Sets crossfading between songs. """ seconds = int(seconds) - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^next$') def next_(context): @@ -89,6 +92,7 @@ def next_(context): """ return context.core.playback.next().get() + @handle_request(r'^pause$') @handle_request(r'^pause "(?P[01])"$') def pause(context, state=None): @@ -113,6 +117,7 @@ def pause(context, state=None): else: context.core.playback.resume() + @handle_request(r'^play$') def play(context): """ @@ -121,6 +126,7 @@ def play(context): """ return context.core.playback.play().get() + @handle_request(r'^playid (?P-?\d+)$') @handle_request(r'^playid "(?P-?\d+)"$') def playid(context, cpid): @@ -149,6 +155,7 @@ def playid(context, cpid): except LookupError: raise MpdNoExistError(u'No such song', command=u'playid') + @handle_request(r'^play (?P-?\d+)$') @handle_request(r'^play "(?P-?\d+)"$') def playpos(context, songpos): @@ -182,9 +189,10 @@ def playpos(context, songpos): except IndexError: raise MpdArgError(u'Bad song index', command=u'play') + def _play_minus_one(context): if (context.core.playback.state.get() == PlaybackState.PLAYING): - return # Nothing to do + return # Nothing to do elif (context.core.playback.state.get() == PlaybackState.PAUSED): return context.core.playback.resume().get() elif context.core.playback.current_cp_track.get() is not None: @@ -194,7 +202,8 @@ def _play_minus_one(context): cp_track = context.core.current_playlist.slice(0, 1).get()[0] return context.core.playback.play(cp_track).get() else: - return # Fail silently + return # Fail silently + @handle_request(r'^previous$') def previous(context): @@ -242,6 +251,7 @@ def previous(context): """ return context.core.playback.previous().get() + @handle_request(r'^random (?P[01])$') @handle_request(r'^random "(?P[01])"$') def random(context, state): @@ -257,6 +267,7 @@ def random(context, state): else: context.core.playback.random = False + @handle_request(r'^repeat (?P[01])$') @handle_request(r'^repeat "(?P[01])"$') def repeat(context, state): @@ -272,6 +283,7 @@ def repeat(context, state): else: context.core.playback.repeat = False + @handle_request(r'^replay_gain_mode "(?P(off|track|album))"$') def replay_gain_mode(context, mode): """ @@ -286,7 +298,8 @@ def replay_gain_mode(context, mode): This command triggers the options idle event. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^replay_gain_status$') def replay_gain_status(context): @@ -298,7 +311,8 @@ def replay_gain_status(context): Prints replay gain options. Currently, only the variable ``replay_gain_mode`` is returned. """ - return u'off' # TODO + return u'off' # TODO + @handle_request(r'^seek (?P\d+) (?P\d+)$') @handle_request(r'^seek "(?P\d+)" "(?P\d+)"$') @@ -319,6 +333,7 @@ def seek(context, songpos, seconds): playpos(context, songpos) context.core.playback.seek(int(seconds) * 1000) + @handle_request(r'^seekid "(?P\d+)" "(?P\d+)"$') def seekid(context, cpid, seconds): """ @@ -332,6 +347,7 @@ def seekid(context, cpid, seconds): playid(context, cpid) context.core.playback.seek(int(seconds) * 1000) + @handle_request(r'^setvol (?P[-+]*\d+)$') @handle_request(r'^setvol "(?P[-+]*\d+)"$') def setvol(context, volume): @@ -353,6 +369,7 @@ def setvol(context, volume): volume = 100 context.core.playback.volume = volume + @handle_request(r'^single (?P[01])$') @handle_request(r'^single "(?P[01])"$') def single(context, state): @@ -370,6 +387,7 @@ def single(context, state): else: context.core.playback.single = False + @handle_request(r'^stop$') def stop(context): """ diff --git a/mopidy/frontends/mpd/protocol/reflection.py b/mopidy/frontends/mpd/protocol/reflection.py index 8cd1337b..bc18eb3a 100644 --- a/mopidy/frontends/mpd/protocol/reflection.py +++ b/mopidy/frontends/mpd/protocol/reflection.py @@ -1,6 +1,7 @@ from mopidy.frontends.mpd.protocol import handle_request, mpd_commands from mopidy.frontends.mpd.exceptions import MpdNotImplemented + @handle_request(r'^commands$', auth_required=False) def commands(context): """ @@ -13,16 +14,20 @@ def commands(context): if context.dispatcher.authenticated: command_names = set([command.name for command in mpd_commands]) else: - command_names = set([command.name for command in mpd_commands + command_names = set([ + command.name for command in mpd_commands if not command.auth_required]) # No one is permited to use kill, rest of commands are not listed by MPD, # so we shouldn't either. - command_names = command_names - set(['kill', 'command_list_begin', - 'command_list_ok_begin', 'command_list_ok_begin', 'command_list_end', - 'idle', 'noidle', 'sticker']) + command_names = command_names - set([ + 'kill', 'command_list_begin', 'command_list_ok_begin', + 'command_list_ok_begin', 'command_list_end', 'idle', 'noidle', + 'sticker']) + + return [ + ('command', command_name) for command_name in sorted(command_names)] - return [('command', command_name) for command_name in sorted(command_names)] @handle_request(r'^decoders$') def decoders(context): @@ -41,7 +46,8 @@ def decoders(context): plugin: mpcdec suffix: mpc """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^notcommands$', auth_required=False) def notcommands(context): @@ -55,13 +61,15 @@ def notcommands(context): if context.dispatcher.authenticated: command_names = [] else: - command_names = [command.name for command in mpd_commands - if command.auth_required] + command_names = [ + command.name for command in mpd_commands if command.auth_required] # No permission to use command_names.append('kill') - return [('command', command_name) for command_name in sorted(command_names)] + return [ + ('command', command_name) for command_name in sorted(command_names)] + @handle_request(r'^tagtypes$') def tagtypes(context): @@ -72,7 +80,8 @@ def tagtypes(context): Shows a list of available song metadata. """ - pass # TODO + pass # TODO + @handle_request(r'^urlhandlers$') def urlhandlers(context): @@ -83,5 +92,6 @@ def urlhandlers(context): Gets a list of available URL handlers. """ - return [(u'handler', uri_scheme) + return [ + (u'handler', uri_scheme) for uri_scheme in context.core.uri_schemes.get()] diff --git a/mopidy/frontends/mpd/protocol/status.py b/mopidy/frontends/mpd/protocol/status.py index 4f48265c..deda4986 100644 --- a/mopidy/frontends/mpd/protocol/status.py +++ b/mopidy/frontends/mpd/protocol/status.py @@ -6,8 +6,10 @@ from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.translator import track_to_mpd_format #: Subsystems that can be registered with idle command. -SUBSYSTEMS = ['database', 'mixer', 'options', 'output', - 'player', 'playlist', 'stored_playlist', 'update', ] +SUBSYSTEMS = [ + 'database', 'mixer', 'options', 'output', 'player', 'playlist', + 'stored_playlist', 'update'] + @handle_request(r'^clearerror$') def clearerror(context): @@ -19,7 +21,8 @@ def clearerror(context): Clears the current error message in status (this is also accomplished by any command that starts playback). """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^currentsong$') def currentsong(context): @@ -36,6 +39,7 @@ def currentsong(context): position = context.core.playback.current_playlist_position.get() return track_to_mpd_format(current_cp_track, position=position) + @handle_request(r'^idle$') @handle_request(r'^idle (?P.+)$') def idle(context, subsystems=None): @@ -93,6 +97,7 @@ def idle(context, subsystems=None): response.append(u'changed: %s' % subsystem) return response + @handle_request(r'^noidle$') def noidle(context): """See :meth:`_status_idle`.""" @@ -102,6 +107,7 @@ def noidle(context): context.events = set() context.session.prevent_timeout = False + @handle_request(r'^stats$') def stats(context): """ @@ -119,15 +125,16 @@ def stats(context): - ``playtime``: time length of music played """ return { - 'artists': 0, # TODO - 'albums': 0, # TODO - 'songs': 0, # TODO - 'uptime': 0, # TODO - 'db_playtime': 0, # TODO - 'db_update': 0, # TODO - 'playtime': 0, # TODO + 'artists': 0, # TODO + 'albums': 0, # TODO + 'songs': 0, # TODO + 'uptime': 0, # TODO + 'db_playtime': 0, # TODO + 'db_update': 0, # TODO + 'playtime': 0, # TODO } + @handle_request(r'^status$') def status(context): """ @@ -153,7 +160,7 @@ def status(context): - ``nextsongid``: playlist songid of the next song to be played - ``time``: total time elapsed (of current playing/paused song) - ``elapsed``: Total time elapsed within the current song, but with - higher resolution. + higher resolution. - ``bitrate``: instantaneous bitrate in kbps - ``xfade``: crossfade in seconds - ``audio``: sampleRate``:bits``:channels @@ -175,8 +182,8 @@ def status(context): 'playback.single': context.core.playback.single, 'playback.state': context.core.playback.state, 'playback.current_cp_track': context.core.playback.current_cp_track, - 'playback.current_playlist_position': - context.core.playback.current_playlist_position, + 'playback.current_playlist_position': ( + context.core.playback.current_playlist_position), 'playback.time_position': context.core.playback.time_position, } pykka.future.get_all(futures.values()) @@ -194,39 +201,47 @@ def status(context): if futures['playback.current_cp_track'].get() is not None: result.append(('song', _status_songpos(futures))) result.append(('songid', _status_songid(futures))) - if futures['playback.state'].get() in (PlaybackState.PLAYING, - PlaybackState.PAUSED): + if futures['playback.state'].get() in ( + PlaybackState.PLAYING, PlaybackState.PAUSED): result.append(('time', _status_time(futures))) result.append(('elapsed', _status_time_elapsed(futures))) result.append(('bitrate', _status_bitrate(futures))) return result + def _status_bitrate(futures): current_cp_track = futures['playback.current_cp_track'].get() if current_cp_track is not None: return current_cp_track.track.bitrate + def _status_consume(futures): if futures['playback.consume'].get(): return 1 else: return 0 + def _status_playlist_length(futures): return futures['current_playlist.length'].get() + def _status_playlist_version(futures): return futures['current_playlist.version'].get() + def _status_random(futures): return int(futures['playback.random'].get()) + def _status_repeat(futures): return int(futures['playback.repeat'].get()) + def _status_single(futures): return int(futures['playback.single'].get()) + def _status_songid(futures): current_cp_track = futures['playback.current_cp_track'].get() if current_cp_track is not None: @@ -234,9 +249,11 @@ def _status_songid(futures): else: return _status_songpos(futures) + def _status_songpos(futures): return futures['playback.current_playlist_position'].get() + def _status_state(futures): state = futures['playback.state'].get() if state == PlaybackState.PLAYING: @@ -246,13 +263,17 @@ def _status_state(futures): elif state == PlaybackState.PAUSED: return u'pause' + def _status_time(futures): - return u'%d:%d' % (futures['playback.time_position'].get() // 1000, + return u'%d:%d' % ( + futures['playback.time_position'].get() // 1000, _status_time_total(futures) // 1000) + def _status_time_elapsed(futures): return u'%.3f' % (futures['playback.time_position'].get() / 1000.0) + def _status_time_total(futures): current_cp_track = futures['playback.current_cp_track'].get() if current_cp_track is None: @@ -262,6 +283,7 @@ def _status_time_total(futures): else: return current_cp_track.track.length + def _status_volume(futures): volume = futures['playback.volume'].get() if volume is not None: @@ -269,5 +291,6 @@ def _status_volume(futures): else: return -1 + def _status_xfade(futures): - return 0 # Not supported + return 0 # Not supported diff --git a/mopidy/frontends/mpd/protocol/stickers.py b/mopidy/frontends/mpd/protocol/stickers.py index c3663ff1..074a306d 100644 --- a/mopidy/frontends/mpd/protocol/stickers.py +++ b/mopidy/frontends/mpd/protocol/stickers.py @@ -1,7 +1,9 @@ from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.exceptions import MpdNotImplemented -@handle_request(r'^sticker delete "(?P[^"]+)" ' + +@handle_request( + r'^sticker delete "(?P[^"]+)" ' r'"(?P[^"]+)"( "(?P[^"]+)")*$') def sticker_delete(context, field, uri, name=None): """ @@ -12,9 +14,11 @@ def sticker_delete(context, field, uri, name=None): Deletes a sticker value from the specified object. If you do not specify a sticker name, all sticker values are deleted. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO -@handle_request(r'^sticker find "(?P[^"]+)" "(?P[^"]+)" ' + +@handle_request( + r'^sticker find "(?P[^"]+)" "(?P[^"]+)" ' r'"(?P[^"]+)"$') def sticker_find(context, field, uri, name): """ @@ -26,9 +30,11 @@ def sticker_find(context, field, uri, name): below the specified directory (``URI``). For each matching song, it prints the ``URI`` and that one sticker's value. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO -@handle_request(r'^sticker get "(?P[^"]+)" "(?P[^"]+)" ' + +@handle_request( + r'^sticker get "(?P[^"]+)" "(?P[^"]+)" ' r'"(?P[^"]+)"$') def sticker_get(context, field, uri, name): """ @@ -38,7 +44,8 @@ def sticker_get(context, field, uri, name): Reads a sticker value for the specified object. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^sticker list "(?P[^"]+)" "(?P[^"]+)"$') def sticker_list(context, field, uri): @@ -49,9 +56,11 @@ def sticker_list(context, field, uri): Lists the stickers for the specified object. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO -@handle_request(r'^sticker set "(?P[^"]+)" "(?P[^"]+)" ' + +@handle_request( + r'^sticker set "(?P[^"]+)" "(?P[^"]+)" ' r'"(?P[^"]+)" "(?P[^"]+)"$') def sticker_set(context, field, uri, name, value): """ @@ -62,4 +71,4 @@ def sticker_set(context, field, uri, name, value): Adds a sticker value to the specified object. If a sticker item with that name already exists, it is replaced. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO diff --git a/mopidy/frontends/mpd/protocol/stored_playlists.py b/mopidy/frontends/mpd/protocol/stored_playlists.py index c21f4714..ed1c38ab 100644 --- a/mopidy/frontends/mpd/protocol/stored_playlists.py +++ b/mopidy/frontends/mpd/protocol/stored_playlists.py @@ -4,6 +4,7 @@ from mopidy.frontends.mpd.exceptions import MpdNoExistError, MpdNotImplemented from mopidy.frontends.mpd.protocol import handle_request from mopidy.frontends.mpd.translator import playlist_to_mpd_format + @handle_request(r'^listplaylist "(?P[^"]+)"$') def listplaylist(context, name): """ @@ -25,6 +26,7 @@ def listplaylist(context, name): except LookupError: raise MpdNoExistError(u'No such playlist', command=u'listplaylist') + @handle_request(r'^listplaylistinfo "(?P[^"]+)"$') def listplaylistinfo(context, name): """ @@ -46,6 +48,7 @@ def listplaylistinfo(context, name): raise MpdNoExistError( u'No such playlist', command=u'listplaylistinfo') + @handle_request(r'^listplaylists$') def listplaylists(context): """ @@ -70,8 +73,8 @@ def listplaylists(context): result = [] for playlist in context.core.stored_playlists.playlists.get(): result.append((u'playlist', playlist.name)) - last_modified = (playlist.last_modified or - dt.datetime.now()).isoformat() + last_modified = ( + playlist.last_modified or dt.datetime.now()).isoformat() # Remove microseconds last_modified = last_modified.split('.')[0] # Add time zone information @@ -80,6 +83,7 @@ def listplaylists(context): result.append((u'Last-Modified', last_modified)) return result + @handle_request(r'^load "(?P[^"]+)"$') def load(context, name): """ @@ -99,6 +103,7 @@ def load(context, name): except LookupError: raise MpdNoExistError(u'No such playlist', command=u'load') + @handle_request(r'^playlistadd "(?P[^"]+)" "(?P[^"]+)"$') def playlistadd(context, name, uri): """ @@ -110,7 +115,8 @@ def playlistadd(context, name, uri): ``NAME.m3u`` will be created if it does not exist. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^playlistclear "(?P[^"]+)"$') def playlistclear(context, name): @@ -121,7 +127,8 @@ def playlistclear(context, name): Clears the playlist ``NAME.m3u``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^playlistdelete "(?P[^"]+)" "(?P\d+)"$') def playlistdelete(context, name, songpos): @@ -132,9 +139,11 @@ def playlistdelete(context, name, songpos): Deletes ``SONGPOS`` from the playlist ``NAME.m3u``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO -@handle_request(r'^playlistmove "(?P[^"]+)" ' + +@handle_request( + r'^playlistmove "(?P[^"]+)" ' r'"(?P\d+)" "(?P\d+)"$') def playlistmove(context, name, from_pos, to_pos): """ @@ -151,7 +160,8 @@ def playlistmove(context, name, from_pos, to_pos): documentation, but just the ``SONGPOS`` to move *from*, i.e. ``playlistmove {NAME} {FROM_SONGPOS} {TO_SONGPOS}``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^rename "(?P[^"]+)" "(?P[^"]+)"$') def rename(context, old_name, new_name): @@ -162,7 +172,8 @@ def rename(context, old_name, new_name): Renames the playlist ``NAME.m3u`` to ``NEW_NAME.m3u``. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^rm "(?P[^"]+)"$') def rm(context, name): @@ -173,7 +184,8 @@ def rm(context, name): Removes the playlist ``NAME.m3u`` from the playlist directory. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO + @handle_request(r'^save "(?P[^"]+)"$') def save(context, name): @@ -185,4 +197,4 @@ def save(context, name): Saves the current playlist to ``NAME.m3u`` in the playlist directory. """ - raise MpdNotImplemented # TODO + raise MpdNotImplemented # TODO diff --git a/mopidy/frontends/mpd/translator.py b/mopidy/frontends/mpd/translator.py index 6ae32c9e..0ab28271 100644 --- a/mopidy/frontends/mpd/translator.py +++ b/mopidy/frontends/mpd/translator.py @@ -6,6 +6,7 @@ from mopidy.frontends.mpd import protocol from mopidy.models import CpTrack from mopidy.utils.path import mtime as get_mtime, uri_to_path, split_path + def track_to_mpd_format(track, position=None): """ Format track for output to MPD client. @@ -48,8 +49,8 @@ def track_to_mpd_format(track, position=None): # FIXME don't use first and best artist? # FIXME don't duplicate following code? if track.album is not None and track.album.artists: - artists = filter(lambda a: a.musicbrainz_id is not None, - track.album.artists) + artists = filter( + lambda a: a.musicbrainz_id is not None, track.album.artists) if artists: result.append( ('MUSICBRAINZ_ALBUMARTISTID', artists[0].musicbrainz_id)) @@ -61,16 +62,19 @@ def track_to_mpd_format(track, position=None): result.append(('MUSICBRAINZ_TRACKID', track.musicbrainz_id)) return result + MPD_KEY_ORDER = ''' key file Time Artist AlbumArtist Title Album Track Date MUSICBRAINZ_ALBUMID MUSICBRAINZ_ALBUMARTISTID MUSICBRAINZ_ARTISTID MUSICBRAINZ_TRACKID mtime '''.split() + def order_mpd_track_info(result): """ - Order results from :func:`mopidy.frontends.mpd.translator.track_to_mpd_format` - so that it matches MPD's ordering. Simply a cosmetic fix for easier - diffing of tag_caches. + Order results from + :func:`mopidy.frontends.mpd.translator.track_to_mpd_format` so that it + matches MPD's ordering. Simply a cosmetic fix for easier diffing of + tag_caches. :param result: the track info :type result: list of tuples @@ -78,6 +82,7 @@ def order_mpd_track_info(result): """ return sorted(result, key=lambda i: MPD_KEY_ORDER.index(i[0])) + def artists_to_mpd_format(artists): """ Format track artists for output to MPD client. @@ -90,6 +95,7 @@ def artists_to_mpd_format(artists): artists.sort(key=lambda a: a.name) return u', '.join([a.name for a in artists if a.name]) + def tracks_to_mpd_format(tracks, start=0, end=None): """ Format list of tracks for output to MPD client. @@ -115,6 +121,7 @@ def tracks_to_mpd_format(tracks, start=0, end=None): result.append(track_to_mpd_format(track, position)) return result + def playlist_to_mpd_format(playlist, *args, **kwargs): """ Format playlist for output to MPD client. @@ -123,6 +130,7 @@ def playlist_to_mpd_format(playlist, *args, **kwargs): """ return tracks_to_mpd_format(playlist.tracks, *args, **kwargs) + def tracks_to_tag_cache_format(tracks): """ Format list of tracks for output to MPD tag cache @@ -141,6 +149,7 @@ def tracks_to_tag_cache_format(tracks): _add_to_tag_cache(result, *tracks_to_directory_tree(tracks)) return result + def _add_to_tag_cache(result, folders, files): music_folder = settings.LOCAL_MUSIC_PATH regexp = '^' + re.escape(music_folder).rstrip('/') + '/?' @@ -165,6 +174,7 @@ def _add_to_tag_cache(result, folders, files): result.extend(track_result) result.append(('songList end',)) + def tracks_to_directory_tree(tracks): directories = ({}, []) for track in tracks: diff --git a/mopidy/frontends/mpris/__init__.py b/mopidy/frontends/mpris/__init__.py index 1a8797f2..80995adf 100644 --- a/mopidy/frontends/mpris/__init__.py +++ b/mopidy/frontends/mpris/__init__.py @@ -5,7 +5,7 @@ logger = logging.getLogger('mopidy.frontends.mpris') try: import indicate except ImportError as import_error: - indicate = None + indicate = None # noqa logger.debug(u'Startup notification will not be sent (%s)', import_error) from pykka.actor import ThreadingActor @@ -100,8 +100,8 @@ class MprisFrontend(ThreadingActor, core.CoreListener): props_with_new_values = [ (p, self.mpris_object.Get(objects.PLAYER_IFACE, p)) for p in changed_properties] - self.mpris_object.PropertiesChanged(objects.PLAYER_IFACE, - dict(props_with_new_values), []) + self.mpris_object.PropertiesChanged( + objects.PLAYER_IFACE, dict(props_with_new_values), []) def track_playback_paused(self, track, time_position): logger.debug(u'Received track playback paused event') diff --git a/mopidy/frontends/mpris/objects.py b/mopidy/frontends/mpris/objects.py index 7c8b6f5a..ee54f91c 100644 --- a/mopidy/frontends/mpris/objects.py +++ b/mopidy/frontends/mpris/objects.py @@ -77,8 +77,8 @@ class MprisObject(dbus.service.Object): def _connect_to_dbus(self): logger.debug(u'Connecting to D-Bus...') mainloop = dbus.mainloop.glib.DBusGMainLoop() - bus_name = dbus.service.BusName(BUS_NAME, - dbus.SessionBus(mainloop=mainloop)) + bus_name = dbus.service.BusName( + BUS_NAME, dbus.SessionBus(mainloop=mainloop)) logger.info(u'Connected to D-Bus') return bus_name @@ -92,9 +92,10 @@ class MprisObject(dbus.service.Object): ### Properties interface @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, - in_signature='ss', out_signature='v') + in_signature='ss', out_signature='v') def Get(self, interface, prop): - logger.debug(u'%s.Get(%s, %s) called', + logger.debug( + u'%s.Get(%s, %s) called', dbus.PROPERTIES_IFACE, repr(interface), repr(prop)) (getter, setter) = self.properties[interface][prop] if callable(getter): @@ -103,35 +104,36 @@ class MprisObject(dbus.service.Object): return getter @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, - in_signature='s', out_signature='a{sv}') + in_signature='s', out_signature='a{sv}') def GetAll(self, interface): - logger.debug(u'%s.GetAll(%s) called', - dbus.PROPERTIES_IFACE, repr(interface)) + logger.debug( + u'%s.GetAll(%s) called', dbus.PROPERTIES_IFACE, repr(interface)) getters = {} for key, (getter, setter) in self.properties[interface].iteritems(): getters[key] = getter() if callable(getter) else getter return getters @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, - in_signature='ssv', out_signature='') + in_signature='ssv', out_signature='') def Set(self, interface, prop, value): - logger.debug(u'%s.Set(%s, %s, %s) called', + logger.debug( + u'%s.Set(%s, %s, %s) called', dbus.PROPERTIES_IFACE, repr(interface), repr(prop), repr(value)) getter, setter = self.properties[interface][prop] if setter is not None: setter(value) - self.PropertiesChanged(interface, - {prop: self.Get(interface, prop)}, []) + self.PropertiesChanged( + interface, {prop: self.Get(interface, prop)}, []) @dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE, - signature='sa{sv}as') + signature='sa{sv}as') def PropertiesChanged(self, interface, changed_properties, - invalidated_properties): - logger.debug(u'%s.PropertiesChanged(%s, %s, %s) signaled', + invalidated_properties): + logger.debug( + u'%s.PropertiesChanged(%s, %s, %s) signaled', dbus.PROPERTIES_IFACE, interface, changed_properties, invalidated_properties) - ### Root interface methods @dbus.service.method(dbus_interface=ROOT_IFACE) @@ -144,7 +146,6 @@ class MprisObject(dbus.service.Object): logger.debug(u'%s.Quit called', ROOT_IFACE) exit_process() - ### Root interface properties def get_DesktopEntry(self): @@ -153,7 +154,6 @@ class MprisObject(dbus.service.Object): def get_SupportedUriSchemes(self): return dbus.Array(self.core.uri_schemes.get(), signature='s') - ### Player interface methods @dbus.service.method(dbus_interface=PLAYER_IFACE) @@ -263,7 +263,6 @@ class MprisObject(dbus.service.Object): else: logger.debug(u'Track with URI "%s" not found in library.', uri) - ### Player interface signals @dbus.service.signal(dbus_interface=PLAYER_IFACE, signature='x') @@ -271,7 +270,6 @@ class MprisObject(dbus.service.Object): logger.debug(u'%s.Seeked signaled', PLAYER_IFACE) # Do nothing, as just calling the method is enough to emit the signal. - ### Player interface properties def get_PlaybackStatus(self): @@ -383,20 +381,23 @@ class MprisObject(dbus.service.Object): def get_CanGoNext(self): if not self.get_CanControl(): return False - return (self.core.playback.cp_track_at_next.get() != + return ( + self.core.playback.cp_track_at_next.get() != self.core.playback.current_cp_track.get()) def get_CanGoPrevious(self): if not self.get_CanControl(): return False - return (self.core.playback.cp_track_at_previous.get() != + return ( + self.core.playback.cp_track_at_previous.get() != self.core.playback.current_cp_track.get()) def get_CanPlay(self): if not self.get_CanControl(): return False - return (self.core.playback.current_track.get() is not None - or self.core.playback.track_at_next.get() is not None) + return ( + self.core.playback.current_track.get() is not None or + self.core.playback.track_at_next.get() is not None) def get_CanPause(self): if not self.get_CanControl(): diff --git a/mopidy/models.py b/mopidy/models.py index 507ca088..8eaa4ee5 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -13,8 +13,9 @@ class ImmutableObject(object): def __init__(self, *args, **kwargs): for key, value in kwargs.items(): if not hasattr(self, key): - raise TypeError('__init__() got an unexpected keyword ' + \ - 'argument \'%s\'' % key) + raise TypeError( + u"__init__() got an unexpected keyword argument '%s'" % + key) self.__dict__[key] = value def __setattr__(self, name, value): @@ -71,8 +72,8 @@ class ImmutableObject(object): if hasattr(self, key): data[key] = values.pop(key) if values: - raise TypeError("copy() got an unexpected keyword argument '%s'" - % key) + raise TypeError( + u"copy() got an unexpected keyword argument '%s'" % key) return self.__class__(**data) def serialize(self): diff --git a/mopidy/scanner.py b/mopidy/scanner.py index 29511c80..2c12d26a 100644 --- a/mopidy/scanner.py +++ b/mopidy/scanner.py @@ -10,6 +10,7 @@ import datetime from mopidy.utils.path import path_to_uri, find_files from mopidy.models import Track, Artist, Album + def translator(data): albumartist_kwargs = {} album_kwargs = {} @@ -37,7 +38,8 @@ def translator(data): _retrieve('musicbrainz-trackid', 'musicbrainz_id', track_kwargs) _retrieve('musicbrainz-artistid', 'musicbrainz_id', artist_kwargs) _retrieve('musicbrainz-albumid', 'musicbrainz_id', album_kwargs) - _retrieve('musicbrainz-albumartistid', 'musicbrainz_id', albumartist_kwargs) + _retrieve( + 'musicbrainz-albumartistid', 'musicbrainz_id', albumartist_kwargs) if albumartist_kwargs: album_kwargs['artists'] = [Artist(**albumartist_kwargs)] @@ -61,8 +63,8 @@ class Scanner(object): self.uribin = gst.element_factory_make('uridecodebin') self.uribin.set_property('caps', gst.Caps('audio/x-raw-int')) - self.uribin.connect('pad-added', self.process_new_pad, - fakesink.get_pad('sink')) + self.uribin.connect( + 'pad-added', self.process_new_pad, fakesink.get_pad('sink')) self.pipe = gst.element_factory_make('pipeline') self.pipe.add(self.uribin) @@ -106,7 +108,7 @@ class Scanner(object): self.next_uri() def get_duration(self): - self.pipe.get_state() # Block until state change is done. + self.pipe.get_state() # Block until state change is done. try: return self.pipe.query_duration( gst.FORMAT_TIME, None)[0] // gst.MSECOND diff --git a/mopidy/utils/__init__.py b/mopidy/utils/__init__.py index aacc2e85..839e4f79 100644 --- a/mopidy/utils/__init__.py +++ b/mopidy/utils/__init__.py @@ -2,7 +2,6 @@ from __future__ import division import locale import logging -import os import sys logger = logging.getLogger('mopidy.utils') diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 2c68e429..d72f1392 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -61,8 +61,8 @@ def platform_info(): def python_info(): return { 'name': 'Python', - 'version': '%s %s' % (platform.python_implementation(), - platform.python_version()), + 'version': '%s %s' % ( + platform.python_implementation(), platform.python_version()), 'path': platform.__file__, } @@ -125,9 +125,11 @@ def _gstreamer_check_elements(): # Shoutcast output 'shout2send', ] - known_elements = [factory.get_name() for factory in + known_elements = [ + factory.get_name() for factory in gst.registry_get_default().get_feature_list(gst.TYPE_ELEMENT_FACTORY)] - return [(element, element in known_elements) for element in elements_to_check] + return [ + (element, element in known_elements) for element in elements_to_check] def pykka_info(): diff --git a/mopidy/utils/log.py b/mopidy/utils/log.py index 191efa2f..9b9495d5 100644 --- a/mopidy/utils/log.py +++ b/mopidy/utils/log.py @@ -3,6 +3,7 @@ import logging.handlers from mopidy import get_version, get_platform, get_python, settings + def setup_logging(verbosity_level, save_debug_log): setup_root_logger() setup_console_logging(verbosity_level) @@ -13,10 +14,12 @@ def setup_logging(verbosity_level, save_debug_log): logger.info(u'Platform: %s', get_platform()) logger.info(u'Python: %s', get_python()) + def setup_root_logger(): root = logging.getLogger('') root.setLevel(logging.DEBUG) + def setup_console_logging(verbosity_level): if verbosity_level == 0: log_level = logging.WARNING @@ -37,6 +40,7 @@ def setup_console_logging(verbosity_level): if verbosity_level < 3: logging.getLogger('pykka').setLevel(logging.INFO) + def setup_debug_logging_to_file(): formatter = logging.Formatter(settings.DEBUG_LOG_FORMAT) handler = logging.handlers.RotatingFileHandler( @@ -46,6 +50,7 @@ def setup_debug_logging_to_file(): root = logging.getLogger('') root.addHandler(handler) + def indent(string, places=4, linebreak='\n'): lines = string.split(linebreak) if len(lines) == 1: diff --git a/mopidy/utils/network.py b/mopidy/utils/network.py index d2e0690b..2a637c9b 100644 --- a/mopidy/utils/network.py +++ b/mopidy/utils/network.py @@ -27,8 +27,10 @@ def try_ipv6_socket(): socket.socket(socket.AF_INET6).close() return True except IOError as error: - logger.debug(u'Platform supports IPv6, but socket ' - 'creation failed, disabling: %s', locale_decode(error)) + logger.debug( + u'Platform supports IPv6, but socket creation failed, ' + u'disabling: %s', + locale_decode(error)) return False @@ -59,7 +61,7 @@ class Server(object): """Setup listener and register it with gobject's event loop.""" def __init__(self, host, port, protocol, protocol_kwargs=None, - max_connections=5, timeout=30): + max_connections=5, timeout=30): self.protocol = protocol self.protocol_kwargs = protocol_kwargs or {} self.max_connections = max_connections @@ -114,8 +116,8 @@ class Server(object): pass def init_connection(self, sock, addr): - Connection(self.protocol, self.protocol_kwargs, - sock, addr, self.timeout) + Connection( + self.protocol, self.protocol_kwargs, sock, addr, self.timeout) class Connection(object): @@ -130,7 +132,7 @@ class Connection(object): def __init__(self, protocol, protocol_kwargs, sock, addr, timeout): sock.setblocking(False) - self.host, self.port = addr[:2] # IPv6 has larger addr + self.host, self.port = addr[:2] # IPv6 has larger addr self.sock = sock self.protocol = protocol @@ -214,7 +216,8 @@ class Connection(object): return try: - self.recv_id = gobject.io_add_watch(self.sock.fileno(), + self.recv_id = gobject.io_add_watch( + self.sock.fileno(), gobject.IO_IN | gobject.IO_ERR | gobject.IO_HUP, self.recv_callback) except socket.error as e: @@ -231,7 +234,8 @@ class Connection(object): return try: - self.send_id = gobject.io_add_watch(self.sock.fileno(), + self.send_id = gobject.io_add_watch( + self.sock.fileno(), gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP, self.send_callback) except socket.error as e: @@ -372,8 +376,10 @@ class LineProtocol(ThreadingActor): try: return line.encode(self.encoding) except UnicodeError: - logger.warning(u'Stopping actor due to encode problem, data ' - 'supplied by client was not valid %s', self.encoding) + logger.warning( + u'Stopping actor due to encode problem, data ' + u'supplied by client was not valid %s', + self.encoding) self.stop() def decode(self, line): @@ -385,8 +391,10 @@ class LineProtocol(ThreadingActor): try: return line.decode(self.encoding) except UnicodeError: - logger.warning(u'Stopping actor due to decode problem, data ' - 'supplied by client was not valid %s', self.encoding) + logger.warning( + u'Stopping actor due to decode problem, data ' + u'supplied by client was not valid %s', + self.encoding) self.stop() def join_lines(self, lines): diff --git a/mopidy/utils/path.py b/mopidy/utils/path.py index 7f1b9233..0cf02a4a 100644 --- a/mopidy/utils/path.py +++ b/mopidy/utils/path.py @@ -18,8 +18,9 @@ XDG_DIRS = { def get_or_create_folder(folder): folder = os.path.expanduser(folder) if os.path.isfile(folder): - raise OSError('A file with the same name as the desired ' \ - 'dir, "%s", already exists.' % folder) + raise OSError( + u'A file with the same name as the desired dir, ' + u'"%s", already exists.' % folder) elif not os.path.isdir(folder): logger.info(u'Creating dir %s', folder) os.makedirs(folder, 0755) @@ -47,7 +48,7 @@ def uri_to_path(uri): path = urllib.url2pathname(re.sub('^file:', '', uri)) else: path = urllib.url2pathname(re.sub('^file://', '', uri)) - return path.encode('latin1').decode('utf-8') # Undo double encoding + return path.encode('latin1').decode('utf-8') # Undo double encoding def split_path(path): diff --git a/mopidy/utils/process.py b/mopidy/utils/process.py index 80d850fe..c45659bb 100644 --- a/mopidy/utils/process.py +++ b/mopidy/utils/process.py @@ -10,30 +10,35 @@ from mopidy import SettingsError logger = logging.getLogger('mopidy.utils.process') + def exit_process(): logger.debug(u'Interrupting main...') thread.interrupt_main() logger.debug(u'Interrupted main') + def exit_handler(signum, frame): """A :mod:`signal` handler which will exit the program on signal.""" signals = dict((k, v) for v, k in signal.__dict__.iteritems() - if v.startswith('SIG') and not v.startswith('SIG_')) + if v.startswith('SIG') and not v.startswith('SIG_')) logger.info(u'Got %s signal', signals[signum]) exit_process() + def stop_actors_by_class(klass): actors = ActorRegistry.get_by_class(klass) logger.debug(u'Stopping %d instance(s) of %s', len(actors), klass.__name__) for actor in actors: actor.stop() + def stop_remaining_actors(): num_actors = len(ActorRegistry.get_all()) while num_actors: logger.error( u'There are actor threads still running, this is probably a bug') - logger.debug(u'Seeing %d actor and %d non-actor thread(s): %s', + logger.debug( + u'Seeing %d actor and %d non-actor thread(s): %s', num_actors, threading.active_count() - num_actors, ', '.join([t.name for t in threading.enumerate()])) logger.debug(u'Stopping %d actor(s)...', num_actors) @@ -41,6 +46,7 @@ def stop_remaining_actors(): num_actors = len(ActorRegistry.get_all()) logger.debug(u'All actors stopped.') + class BaseThread(threading.Thread): def __init__(self): super(BaseThread, self).__init__() diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 5468b9bf..0ecdd827 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -32,7 +32,8 @@ class SettingsProxy(object): return self._get_settings_dict_from_module(local_settings_module) def _get_settings_dict_from_module(self, module): - settings = filter(lambda (key, value): self._is_setting(key), + settings = filter( + lambda (key, value): self._is_setting(key), module.__dict__.iteritems()) return dict(settings) @@ -50,7 +51,7 @@ class SettingsProxy(object): if not self._is_setting(attr): return - current = self.current # bind locally to avoid copying+updates + current = self.current # bind locally to avoid copying+updates if attr not in current: raise SettingsError(u'Setting "%s" is not set.' % attr) @@ -73,7 +74,8 @@ class SettingsProxy(object): if interactive: self._read_missing_settings_from_stdin(self.current, self.runtime) if self.get_errors(): - logger.error(u'Settings validation errors: %s', + logger.error( + u'Settings validation errors: %s', log.indent(self.get_errors_as_string())) raise SettingsError(u'Settings validation failed.') @@ -84,11 +86,13 @@ class SettingsProxy(object): def _read_from_stdin(self, prompt): if u'_PASSWORD' in prompt: - return (getpass.getpass(prompt) + return ( + getpass.getpass(prompt) .decode(sys.stdin.encoding, 'ignore')) else: sys.stdout.write(prompt) - return (sys.stdin.readline().strip() + return ( + sys.stdin.readline().strip() .decode(sys.stdin.encoding, 'ignore')) def get_errors(self): @@ -201,7 +205,8 @@ def format_settings_list(settings): lines.append(u'%s: %s' % ( key, log.indent(pprint.pformat(masked_value), places=2))) if value != default_value and default_value is not None: - lines.append(u' Default: %s' % + lines.append( + u' Default: %s' % log.indent(pprint.pformat(default_value), places=4)) if errors.get(key) is not None: lines.append(u' Error: %s' % errors[key]) @@ -235,13 +240,13 @@ def levenshtein(a, b, max=3): if n > m: return levenshtein(b, a) - current = xrange(n+1) - for i in xrange(1, m+1): + current = xrange(n + 1) + for i in xrange(1, m + 1): previous, current = current, [i] + [0] * n - for j in xrange(1, n+1): - add, delete = previous[j] + 1, current[j-1] + 1 - change = previous[j-1] - if a[j-1] != b[i-1]: + for j in xrange(1, n + 1): + add, delete = previous[j] + 1, current[j - 1] + 1 + change = previous[j - 1] + if a[j - 1] != b[i - 1]: change += 1 current[j] = min(add, delete, change) return current[n]