From aede9762f8d442d502552d389bb46a3acb3d2272 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:07:23 +0200 Subject: [PATCH 01/15] Split BaseProcess snd CoreProcess into two files --- mopidy/__main__.py | 2 +- mopidy/backends/libspotify/playback.py | 2 +- mopidy/{process.py => core.py} | 37 ++----------------------- mopidy/frontends/mpd/session.py | 2 +- mopidy/mixers/gstreamer_software.py | 2 +- mopidy/mixers/nad.py | 2 +- mopidy/outputs/gstreamer.py | 2 +- mopidy/utils/process.py | 38 ++++++++++++++++++++++++++ 8 files changed, 46 insertions(+), 41 deletions(-) rename mopidy/{process.py => core.py} (63%) create mode 100644 mopidy/utils/process.py diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 1c0318e7..ac090f16 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -10,7 +10,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))) from mopidy import get_version, settings, SettingsError -from mopidy.process import CoreProcess +from mopidy.core import CoreProcess from mopidy.utils import get_class from mopidy.utils.path import get_or_create_folder from mopidy.utils.settings import list_settings_optparse_callback diff --git a/mopidy/backends/libspotify/playback.py b/mopidy/backends/libspotify/playback.py index 1195e9bc..ed5ba697 100644 --- a/mopidy/backends/libspotify/playback.py +++ b/mopidy/backends/libspotify/playback.py @@ -4,7 +4,7 @@ import multiprocessing from spotify import Link, SpotifyError from mopidy.backends.base import BasePlaybackController -from mopidy.process import pickle_connection +from mopidy.utils.process import pickle_connection logger = logging.getLogger('mopidy.backends.libspotify.playback') diff --git a/mopidy/process.py b/mopidy/core.py similarity index 63% rename from mopidy/process.py rename to mopidy/core.py index 008129b3..06e87294 100644 --- a/mopidy/process.py +++ b/mopidy/core.py @@ -1,42 +1,9 @@ import logging import multiprocessing -from multiprocessing.reduction import reduce_connection -import pickle -import sys -from mopidy import SettingsError - -logger = logging.getLogger('mopidy.process') - -def pickle_connection(connection): - return pickle.dumps(reduce_connection(connection)) - -def unpickle_connection(pickled_connection): - # From http://stackoverflow.com/questions/1446004 - (func, args) = pickle.loads(pickled_connection) - return func(*args) - - -class BaseProcess(multiprocessing.Process): - def run(self): - try: - self.run_inside_try() - except KeyboardInterrupt: - logger.info(u'Interrupted by user') - sys.exit(0) - except SettingsError as e: - logger.error(e.message) - sys.exit(1) - except ImportError as e: - logger.error(e) - sys.exit(1) - except Exception as e: - logger.exception(e) - raise e - - def run_inside_try(self): - raise NotImplementedError +from mopidy.utils.process import BaseProcess, unpickle_connection +logger = logging.getLogger('mopidy.core') class CoreProcess(BaseProcess): def __init__(self, core_queue, output_class, backend_class, frontend): diff --git a/mopidy/frontends/mpd/session.py b/mopidy/frontends/mpd/session.py index e5d2d12d..a9eba73e 100644 --- a/mopidy/frontends/mpd/session.py +++ b/mopidy/frontends/mpd/session.py @@ -3,8 +3,8 @@ import logging import multiprocessing from mopidy.frontends.mpd.protocol import ENCODING, LINE_TERMINATOR, VERSION -from mopidy.process import pickle_connection from mopidy.utils import indent +from mopidy.utils.process import pickle_connection logger = logging.getLogger('mopidy.frontends.mpd.session') diff --git a/mopidy/mixers/gstreamer_software.py b/mopidy/mixers/gstreamer_software.py index 2910ef72..1225cafd 100644 --- a/mopidy/mixers/gstreamer_software.py +++ b/mopidy/mixers/gstreamer_software.py @@ -1,7 +1,7 @@ import multiprocessing from mopidy.mixers import BaseMixer -from mopidy.process import pickle_connection +from mopidy.utils.process import pickle_connection class GStreamerSoftwareMixer(BaseMixer): """Mixer which uses GStreamer to control volume in software.""" diff --git a/mopidy/mixers/nad.py b/mopidy/mixers/nad.py index d78863aa..b8a4f41a 100644 --- a/mopidy/mixers/nad.py +++ b/mopidy/mixers/nad.py @@ -3,9 +3,9 @@ from serial import Serial from multiprocessing import Pipe from mopidy.mixers import BaseMixer -from mopidy.process import BaseProcess from mopidy.settings import (MIXER_EXT_PORT, MIXER_EXT_SOURCE, MIXER_EXT_SPEAKERS_A, MIXER_EXT_SPEAKERS_B) +from mopidy.utils.process import BaseProcess logger = logging.getLogger('mopidy.mixers.nad') diff --git a/mopidy/outputs/gstreamer.py b/mopidy/outputs/gstreamer.py index ca5a98c5..815edbad 100644 --- a/mopidy/outputs/gstreamer.py +++ b/mopidy/outputs/gstreamer.py @@ -8,7 +8,7 @@ import gst import logging import threading -from mopidy.process import BaseProcess, unpickle_connection +from mopidy.utils.process import BaseProcess, unpickle_connection logger = logging.getLogger('mopidy.outputs.gstreamer') diff --git a/mopidy/utils/process.py b/mopidy/utils/process.py new file mode 100644 index 00000000..5e783b73 --- /dev/null +++ b/mopidy/utils/process.py @@ -0,0 +1,38 @@ +import logging +import multiprocessing +from multiprocessing.reduction import reduce_connection +import pickle +import sys + +from mopidy import SettingsError + +logger = logging.getLogger('mopidy.utils.process') + +def pickle_connection(connection): + return pickle.dumps(reduce_connection(connection)) + +def unpickle_connection(pickled_connection): + # From http://stackoverflow.com/questions/1446004 + (func, args) = pickle.loads(pickled_connection) + return func(*args) + + +class BaseProcess(multiprocessing.Process): + def run(self): + try: + self.run_inside_try() + except KeyboardInterrupt: + logger.info(u'Interrupted by user') + sys.exit(0) + except SettingsError as e: + logger.error(e.message) + sys.exit(1) + except ImportError as e: + logger.error(e) + sys.exit(1) + except Exception as e: + logger.exception(e) + raise e + + def run_inside_try(self): + raise NotImplementedError From d43ddab5908a543236a05860fb15658ec154aa5b Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:24:33 +0200 Subject: [PATCH 02/15] Fix import in test --- tests/outputs/gstreamer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/outputs/gstreamer_test.py b/tests/outputs/gstreamer_test.py index c063aaee..5f681f23 100644 --- a/tests/outputs/gstreamer_test.py +++ b/tests/outputs/gstreamer_test.py @@ -2,8 +2,8 @@ import multiprocessing import unittest from mopidy.outputs.gstreamer import GStreamerOutput -from mopidy.process import pickle_connection from mopidy.utils.path import path_to_uri +from mopidy.utils.process import pickle_connection from tests import data_folder, SkipTest From 88a4d64a5946250e2093e8371081384062e1b4bd Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:24:56 +0200 Subject: [PATCH 03/15] Move MPD server into its own process --- docs/changes.rst | 5 +++-- mopidy/__main__.py | 3 ++- mopidy/frontends/mpd/__init__.py | 7 +++---- mopidy/frontends/mpd/process.py | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 mopidy/frontends/mpd/process.py diff --git a/docs/changes.rst b/docs/changes.rst index 7c2ce19d..4fdc8c1f 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -39,8 +39,6 @@ greatly improved MPD client support. the packages created by ``setup.py`` for i.e. PyPI. - MPD frontend: - - Relocate from :mod:`mopidy.mpd` to :mod:`mopidy.frontends.mpd`. - - Split gigantic protocol implementation into eleven modules. - Search improvements, including support for multi-word search. - Fixed ``play "-1"`` and ``playid "-1"`` behaviour when playlist is empty or when a current track is set. @@ -56,11 +54,14 @@ greatly improved MPD client support. - Fix ``load`` so that one can append a playlist to the current playlist, and make it return the correct error message if the playlist is not found. - Support for single track repeat added. (Fixes: :issue:`4`) + - Relocate from :mod:`mopidy.mpd` to :mod:`mopidy.frontends.mpd`. + - Split gigantic protocol implementation into eleven modules. - Rename ``mopidy.frontends.mpd.{serializer => translator}`` to match naming in backends. - Remove setting :attr:`mopidy.settings.SERVER` and :attr:`mopidy.settings.FRONTEND` in favour of the new :attr:`mopidy.settings.FRONTENDS`. + - Run MPD server in its own process. - Backends: diff --git a/mopidy/__main__.py b/mopidy/__main__.py index ac090f16..247c68b3 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -30,7 +30,8 @@ def main(): frontend.start_server(core_queue) core = CoreProcess(core_queue, output_class, backend_class, frontend) core.start() - asyncore.loop() + #asyncore.loop() + logger.debug('Main done') def _parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % get_version()) diff --git a/mopidy/frontends/mpd/__init__.py b/mopidy/frontends/mpd/__init__.py index 53f2003f..048f5748 100644 --- a/mopidy/frontends/mpd/__init__.py +++ b/mopidy/frontends/mpd/__init__.py @@ -1,5 +1,5 @@ from mopidy.frontends.mpd.dispatcher import MpdDispatcher -from mopidy.frontends.mpd.server import MpdServer +from mopidy.frontends.mpd.process import MpdProcess class MpdFrontend(object): """ @@ -17,8 +17,8 @@ class MpdFrontend(object): :param core_queue: the core queue :type core_queue: :class:`multiprocessing.Queue` """ - self.server = MpdServer(core_queue) - self.server.start() + self.process = MpdProcess(core_queue) + self.process.start() def create_dispatcher(self, backend): """ @@ -28,6 +28,5 @@ class MpdFrontend(object): :type backend: :class:`mopidy.backends.base.BaseBackend` :rtype: :class:`mopidy.frontends.mpd.dispatcher.MpdDispatcher` """ - self.dispatcher = MpdDispatcher(backend) return self.dispatcher diff --git a/mopidy/frontends/mpd/process.py b/mopidy/frontends/mpd/process.py new file mode 100644 index 00000000..95ae855f --- /dev/null +++ b/mopidy/frontends/mpd/process.py @@ -0,0 +1,18 @@ +import asyncore +import logging + +from mopidy.frontends.mpd.server import MpdServer +from mopidy.utils.process import BaseProcess + +logger = logging.getLogger('mopidy.frontends.mpd.process') + +class MpdProcess(BaseProcess): + def __init__(self, core_queue): + super(MpdProcess, self).__init__() + self.core_queue = core_queue + + def run_inside_try(self): + logger.debug(u'Starting MPD server process') + server = MpdServer(self.core_queue) + server.start() + asyncore.loop() From 560b8be86f300789f140b34317e04228606b916c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:31:56 +0200 Subject: [PATCH 04/15] Move log setup to mopidy.utils.log --- mopidy/__main__.py | 29 ++--------------------------- mopidy/utils/log.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 mopidy/utils/log.py diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 247c68b3..fb22ddde 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -1,6 +1,4 @@ -import asyncore import logging -import logging.handlers import multiprocessing import optparse import os @@ -12,6 +10,7 @@ sys.path.insert(0, from mopidy import get_version, settings, SettingsError from mopidy.core import CoreProcess from mopidy.utils import get_class +from mopidy.utils.log import setup_logging from mopidy.utils.path import get_or_create_folder from mopidy.utils.settings import list_settings_optparse_callback @@ -19,7 +18,7 @@ logger = logging.getLogger('mopidy.main') def main(): options = _parse_options() - _setup_logging(options.verbosity_level, options.dump) + setup_logging(options.verbosity_level, options.dump) settings.validate() logger.info('-- Starting Mopidy --') get_or_create_folder('~/.mopidy/') @@ -30,7 +29,6 @@ def main(): frontend.start_server(core_queue) core = CoreProcess(core_queue, output_class, backend_class, frontend) core.start() - #asyncore.loop() logger.debug('Main done') def _parse_options(): @@ -49,29 +47,6 @@ def _parse_options(): help='list current settings') return parser.parse_args()[0] -def _setup_logging(verbosity_level, dump): - _setup_console_logging(verbosity_level) - if dump: - _setup_dump_logging() - -def _setup_console_logging(verbosity_level): - if verbosity_level == 0: - level = logging.WARNING - elif verbosity_level == 2: - level = logging.DEBUG - else: - level = logging.INFO - logging.basicConfig(format=settings.CONSOLE_LOG_FORMAT, level=level) - -def _setup_dump_logging(): - root = logging.getLogger('') - root.setLevel(logging.DEBUG) - formatter = logging.Formatter(settings.DUMP_LOG_FORMAT) - handler = logging.handlers.RotatingFileHandler( - settings.DUMP_LOG_FILENAME, maxBytes=102400, backupCount=3) - handler.setFormatter(formatter) - root.addHandler(handler) - if __name__ == '__main__': try: main() diff --git a/mopidy/utils/log.py b/mopidy/utils/log.py new file mode 100644 index 00000000..e75a6df6 --- /dev/null +++ b/mopidy/utils/log.py @@ -0,0 +1,28 @@ +import logging +import logging.handlers + +from mopidy import settings + +def setup_logging(verbosity_level, dump): + setup_console_logging(verbosity_level) + if dump: + setup_dump_logging() + +def setup_console_logging(verbosity_level): + if verbosity_level == 0: + level = logging.WARNING + elif verbosity_level == 2: + level = logging.DEBUG + else: + level = logging.INFO + logging.basicConfig(format=settings.CONSOLE_LOG_FORMAT, level=level) + +def setup_dump_logging(): + root = logging.getLogger('') + root.setLevel(logging.DEBUG) + formatter = logging.Formatter(settings.DUMP_LOG_FORMAT) + handler = logging.handlers.RotatingFileHandler( + settings.DUMP_LOG_FILENAME, maxBytes=102400, backupCount=3) + handler.setFormatter(formatter) + root.addHandler(handler) + From f73800f8e4ccd76d858c08d8cc8a72a6f2274fb6 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:41:54 +0200 Subject: [PATCH 05/15] Validate settings a tad later --- mopidy/__main__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index fb22ddde..a0a91fca 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -17,11 +17,14 @@ from mopidy.utils.settings import list_settings_optparse_callback logger = logging.getLogger('mopidy.main') def main(): - options = _parse_options() + options = parse_options() setup_logging(options.verbosity_level, options.dump) - settings.validate() + logger.info('-- Starting Mopidy --') + get_or_create_folder('~/.mopidy/') + settings.validate() + core_queue = multiprocessing.Queue() output_class = get_class(settings.OUTPUT) backend_class = get_class(settings.BACKENDS[0]) @@ -29,9 +32,10 @@ def main(): frontend.start_server(core_queue) core = CoreProcess(core_queue, output_class, backend_class, frontend) core.start() + logger.debug('Main done') -def _parse_options(): +def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % get_version()) parser.add_option('-q', '--quiet', action='store_const', const=0, dest='verbosity_level', From 60bca18b467ab5e97217c39223d835365c78188a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:52:20 +0200 Subject: [PATCH 06/15] Run CoreProcess in the main process --- mopidy/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index a0a91fca..e56b82ab 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -31,9 +31,9 @@ def main(): frontend = get_class(settings.FRONTENDS[0])() frontend.start_server(core_queue) core = CoreProcess(core_queue, output_class, backend_class, frontend) - core.start() - logger.debug('Main done') + # Explictly call run instead of start, so it runs in this process + core.run() def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % get_version()) From ea699eb121c5c1dad32fd4246355e2d2ee1de9aa Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:59:14 +0200 Subject: [PATCH 07/15] Name all processes --- mopidy/core.py | 2 +- mopidy/frontends/mpd/process.py | 2 +- mopidy/mixers/nad.py | 2 +- mopidy/outputs/gstreamer.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index 06e87294..615fde26 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -7,7 +7,7 @@ logger = logging.getLogger('mopidy.core') class CoreProcess(BaseProcess): def __init__(self, core_queue, output_class, backend_class, frontend): - super(CoreProcess, self).__init__() + super(CoreProcess, self).__init__(name='CoreProcess') self.core_queue = core_queue self.output_queue = None self.output_class = output_class diff --git a/mopidy/frontends/mpd/process.py b/mopidy/frontends/mpd/process.py index 95ae855f..7bd95900 100644 --- a/mopidy/frontends/mpd/process.py +++ b/mopidy/frontends/mpd/process.py @@ -8,7 +8,7 @@ logger = logging.getLogger('mopidy.frontends.mpd.process') class MpdProcess(BaseProcess): def __init__(self, core_queue): - super(MpdProcess, self).__init__() + super(MpdProcess, self).__init__(name='MpdProcess') self.core_queue = core_queue def run_inside_try(self): diff --git a/mopidy/mixers/nad.py b/mopidy/mixers/nad.py index b8a4f41a..f859791b 100644 --- a/mopidy/mixers/nad.py +++ b/mopidy/mixers/nad.py @@ -74,7 +74,7 @@ class NadTalker(BaseProcess): _nad_volume = None def __init__(self, pipe=None): - super(NadTalker, self).__init__() + super(NadTalker, self).__init__(name='NadTalker') self.pipe = pipe self._device = None diff --git a/mopidy/outputs/gstreamer.py b/mopidy/outputs/gstreamer.py index 815edbad..a1544f87 100644 --- a/mopidy/outputs/gstreamer.py +++ b/mopidy/outputs/gstreamer.py @@ -49,7 +49,7 @@ class GStreamerProcess(BaseProcess): ]) def __init__(self, core_queue, output_queue): - super(GStreamerProcess, self).__init__() + super(GStreamerProcess, self).__init__(name='GStreamerProcess') self.core_queue = core_queue self.output_queue = output_queue self.gst_pipeline = None From 51b5910e685874e42b32a4399878774fb3afb6bb Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 01:59:27 +0200 Subject: [PATCH 08/15] Add process name to BaseProcess logging --- mopidy/utils/process.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mopidy/utils/process.py b/mopidy/utils/process.py index 5e783b73..73224840 100644 --- a/mopidy/utils/process.py +++ b/mopidy/utils/process.py @@ -19,10 +19,11 @@ def unpickle_connection(pickled_connection): class BaseProcess(multiprocessing.Process): def run(self): + logger.debug(u'%s: Starting process', self.name) try: self.run_inside_try() except KeyboardInterrupt: - logger.info(u'Interrupted by user') + logger.info(u'%s: Interrupted by user', self.name) sys.exit(0) except SettingsError as e: logger.error(e.message) From 7f95a3b0ba58bfb919636169a991eb17e1668b7f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 03:27:20 +0200 Subject: [PATCH 09/15] Move initialization from main to core --- mopidy/__main__.py | 11 +---------- mopidy/core.py | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index e56b82ab..86a4d5c4 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -1,5 +1,4 @@ import logging -import multiprocessing import optparse import os import sys @@ -9,7 +8,6 @@ sys.path.insert(0, from mopidy import get_version, settings, SettingsError from mopidy.core import CoreProcess -from mopidy.utils import get_class from mopidy.utils.log import setup_logging from mopidy.utils.path import get_or_create_folder from mopidy.utils.settings import list_settings_optparse_callback @@ -25,15 +23,8 @@ def main(): get_or_create_folder('~/.mopidy/') settings.validate() - core_queue = multiprocessing.Queue() - output_class = get_class(settings.OUTPUT) - backend_class = get_class(settings.BACKENDS[0]) - frontend = get_class(settings.FRONTENDS[0])() - frontend.start_server(core_queue) - core = CoreProcess(core_queue, output_class, backend_class, frontend) - # Explictly call run instead of start, so it runs in this process - core.run() + CoreProcess(options).run() def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % get_version()) diff --git a/mopidy/core.py b/mopidy/core.py index 615fde26..0d60b602 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -1,20 +1,19 @@ import logging import multiprocessing +from mopidy import settings +from mopidy.utils import get_class from mopidy.utils.process import BaseProcess, unpickle_connection logger = logging.getLogger('mopidy.core') class CoreProcess(BaseProcess): - def __init__(self, core_queue, output_class, backend_class, frontend): + def __init__(self, options): super(CoreProcess, self).__init__(name='CoreProcess') - self.core_queue = core_queue + self.options = options + self.core_queue = multiprocessing.Queue() self.output_queue = None - self.output_class = output_class - self.backend_class = backend_class - self.output = None self.backend = None - self.frontend = frontend self.dispatcher = None def run_inside_try(self): @@ -24,10 +23,22 @@ class CoreProcess(BaseProcess): self.process_message(message) def setup(self): + self.setup_output() + self.setup_backend() + self.setup_frontend() + + def setup_output(self): self.output_queue = multiprocessing.Queue() - self.output = self.output_class(self.core_queue, self.output_queue) - self.backend = self.backend_class(self.core_queue, self.output_queue) - self.dispatcher = self.frontend.create_dispatcher(self.backend) + get_class(settings.OUTPUT)(self.core_queue, self.output_queue) + + def setup_backend(self): + self.backend = get_class(settings.BACKENDS[0])( + self.core_queue, self.output_queue) + + def setup_frontend(self): + frontend = get_class(settings.FRONTENDS[0])() + frontend.start_server(self.core_queue) + self.dispatcher = frontend.create_dispatcher(self.backend) def process_message(self, message): if message.get('to') == 'output': From aba0cc3ef36fe191bd53bf8695ffe09ef3269ea4 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 12:34:13 +0200 Subject: [PATCH 10/15] Remove redundant error handling, as all these cases are handled in BaseProcess --- mopidy/__main__.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 86a4d5c4..02bdb4e5 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -43,14 +43,4 @@ def parse_options(): return parser.parse_args()[0] if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - logger.info(u'Interrupted by user') - sys.exit(0) - except SettingsError, e: - logger.error(e) - sys.exit(1) - except SystemExit, e: - logger.error(e) - sys.exit(1) + main() From 461830924a25641ac54834b582217391f9b2fef2 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 12:34:41 +0200 Subject: [PATCH 11/15] libspotify thread should not stop Mopidy from exiting, and is thus a daemon thread --- mopidy/backends/libspotify/session_manager.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mopidy/backends/libspotify/session_manager.py b/mopidy/backends/libspotify/session_manager.py index 707423aa..9ea8386b 100644 --- a/mopidy/backends/libspotify/session_manager.py +++ b/mopidy/backends/libspotify/session_manager.py @@ -19,6 +19,9 @@ class LibspotifySessionManager(SpotifySessionManager, threading.Thread): def __init__(self, username, password, core_queue, output_queue): SpotifySessionManager.__init__(self, username, password) threading.Thread.__init__(self) + # Run as a daemon thread, so Mopidy won't wait for this thread to exit + # before Mopidy exits. + self.daemon = True self.core_queue = core_queue self.output_queue = output_queue self.connected = threading.Event() From 5ea3e40594ee0b222ed131d1340f743912ef75c5 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 12:38:33 +0200 Subject: [PATCH 12/15] Rename Thread-1 => LibspotifySessionManagerThread --- mopidy/backends/libspotify/session_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/backends/libspotify/session_manager.py b/mopidy/backends/libspotify/session_manager.py index 9ea8386b..22cbb0a0 100644 --- a/mopidy/backends/libspotify/session_manager.py +++ b/mopidy/backends/libspotify/session_manager.py @@ -18,7 +18,7 @@ class LibspotifySessionManager(SpotifySessionManager, threading.Thread): def __init__(self, username, password, core_queue, output_queue): SpotifySessionManager.__init__(self, username, password) - threading.Thread.__init__(self) + threading.Thread.__init__(self, name='LibspotifySessionManagerThread') # Run as a daemon thread, so Mopidy won't wait for this thread to exit # before Mopidy exits. self.daemon = True From 79729e653b838740ff543fa3de667e4078cf6fc0 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 12:54:18 +0200 Subject: [PATCH 13/15] Make CoreProcess.setup() more functional to show dependencies explicitly --- mopidy/__main__.py | 2 +- mopidy/core.py | 32 ++++++++++++++++---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 02bdb4e5..044e6ec6 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -24,7 +24,7 @@ def main(): settings.validate() # Explictly call run instead of start, so it runs in this process - CoreProcess(options).run() + CoreProcess().run() def parse_options(): parser = optparse.OptionParser(version='Mopidy %s' % get_version()) diff --git a/mopidy/core.py b/mopidy/core.py index 0d60b602..b45a9b96 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -8,13 +8,12 @@ from mopidy.utils.process import BaseProcess, unpickle_connection logger = logging.getLogger('mopidy.core') class CoreProcess(BaseProcess): - def __init__(self, options): + def __init__(self): super(CoreProcess, self).__init__(name='CoreProcess') - self.options = options self.core_queue = multiprocessing.Queue() self.output_queue = None self.backend = None - self.dispatcher = None + self.frontend = None def run_inside_try(self): self.setup() @@ -23,28 +22,29 @@ class CoreProcess(BaseProcess): self.process_message(message) def setup(self): - self.setup_output() - self.setup_backend() - self.setup_frontend() + self.output_queue = self.setup_output(self.core_queue) + self.backend = self.setup_backend(self.core_queue, self.output_queue) + self.frontend = self.setup_frontend(self.core_queue, self.backend) - def setup_output(self): - self.output_queue = multiprocessing.Queue() - get_class(settings.OUTPUT)(self.core_queue, self.output_queue) + def setup_output(self, core_queue): + output_queue = multiprocessing.Queue() + get_class(settings.OUTPUT)(core_queue, output_queue) + return output_queue - def setup_backend(self): - self.backend = get_class(settings.BACKENDS[0])( - self.core_queue, self.output_queue) + def setup_backend(self, core_queue, output_queue): + return get_class(settings.BACKENDS[0])(core_queue, output_queue) - def setup_frontend(self): + def setup_frontend(self, core_queue, backend): frontend = get_class(settings.FRONTENDS[0])() - frontend.start_server(self.core_queue) - self.dispatcher = frontend.create_dispatcher(self.backend) + frontend.start_server(core_queue) + frontend.create_dispatcher(backend) + return frontend def process_message(self, message): if message.get('to') == 'output': self.output_queue.put(message) elif message['command'] == 'mpd_request': - response = self.dispatcher.handle_request(message['request']) + response = self.frontend.dispatcher.handle_request(message['request']) connection = unpickle_connection(message['reply_to']) connection.send(response) elif message['command'] == 'end_of_track': From 976086ae65d2948c9b91e0bd6b7a3724872ffb3f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 16:17:22 +0200 Subject: [PATCH 14/15] Move options parsing, logging setup and settings validation into CoreProcess --- mopidy/__main__.py | 42 +++++------------------------------------- mopidy/core.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 044e6ec6..8aee976b 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -1,46 +1,14 @@ -import logging -import optparse import os import sys +# 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__), '../'))) -from mopidy import get_version, settings, SettingsError from mopidy.core import CoreProcess -from mopidy.utils.log import setup_logging -from mopidy.utils.path import get_or_create_folder -from mopidy.utils.settings import list_settings_optparse_callback - -logger = logging.getLogger('mopidy.main') - -def main(): - options = parse_options() - setup_logging(options.verbosity_level, options.dump) - - logger.info('-- Starting Mopidy --') - - get_or_create_folder('~/.mopidy/') - settings.validate() - - # Explictly call run instead of start, so it runs in this process - CoreProcess().run() - -def parse_options(): - parser = optparse.OptionParser(version='Mopidy %s' % get_version()) - parser.add_option('-q', '--quiet', - action='store_const', const=0, dest='verbosity_level', - help='less output (warning level)') - parser.add_option('-v', '--verbose', - action='store_const', const=2, dest='verbosity_level', - help='more output (debug level)') - parser.add_option('--dump', - action='store_true', dest='dump', - help='dump debug log to file') - parser.add_option('--list-settings', - action='callback', callback=list_settings_optparse_callback, - help='list current settings') - return parser.parse_args()[0] if __name__ == '__main__': - main() + # Explictly call run() instead of start(), since we don't need to start + # another process. + CoreProcess().run() diff --git a/mopidy/core.py b/mopidy/core.py index b45a9b96..d823bfa5 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -1,9 +1,13 @@ import logging import multiprocessing +import optparse -from mopidy import settings +from mopidy import get_version, settings from mopidy.utils import get_class +from mopidy.utils.log import setup_logging +from mopidy.utils.path import get_or_create_folder from mopidy.utils.process import BaseProcess, unpickle_connection +from mopidy.utils.settings import list_settings_optparse_callback logger = logging.getLogger('mopidy.core') @@ -11,21 +15,48 @@ class CoreProcess(BaseProcess): def __init__(self): super(CoreProcess, self).__init__(name='CoreProcess') self.core_queue = multiprocessing.Queue() + self.options = self.parse_options() self.output_queue = None self.backend = None self.frontend = None + def parse_options(self): + parser = optparse.OptionParser(version='Mopidy %s' % get_version()) + parser.add_option('-q', '--quiet', + action='store_const', const=0, dest='verbosity_level', + help='less output (warning level)') + parser.add_option('-v', '--verbose', + action='store_const', const=2, dest='verbosity_level', + help='more output (debug level)') + parser.add_option('--dump', + action='store_true', dest='dump', + help='dump debug log to file') + parser.add_option('--list-settings', + action='callback', callback=list_settings_optparse_callback, + help='list current settings') + return parser.parse_args()[0] + def run_inside_try(self): + logger.info(u'-- Starting Mopidy --') self.setup() while True: message = self.core_queue.get() self.process_message(message) def setup(self): + self.setup_logging() + self.setup_settings() self.output_queue = self.setup_output(self.core_queue) self.backend = self.setup_backend(self.core_queue, self.output_queue) self.frontend = self.setup_frontend(self.core_queue, self.backend) + def setup_logging(self): + setup_logging(self.options.verbosity_level, self.options.dump) + + def setup_settings(self): + get_or_create_folder('~/.mopidy/') + settings.validate() + def setup_output(self, core_queue): output_queue = multiprocessing.Queue() get_class(settings.OUTPUT)(core_queue, output_queue) From 19c4f1c09f4273661bec639cba80a090e368d7e4 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 20 Aug 2010 16:21:07 +0200 Subject: [PATCH 15/15] Readd main() method, to not break bin/mopidy --- mopidy/__main__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index 8aee976b..20e78f5a 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -8,7 +8,10 @@ sys.path.insert(0, from mopidy.core import CoreProcess -if __name__ == '__main__': +def main(): # Explictly call run() instead of start(), since we don't need to start # another process. CoreProcess().run() + +if __name__ == '__main__': + main()