From 5fcc4e67aa12eff00bfa3d56109bbde6f01ff59a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 21:55:01 +0200 Subject: [PATCH 01/27] Add --list-deps command with Pykka adapter --- mopidy/core.py | 4 ++++ mopidy/utils/deps.py | 43 ++++++++++++++++++++++++++++++++++++++++ tests/utils/deps_test.py | 27 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 mopidy/utils/deps.py create mode 100644 tests/utils/deps_test.py diff --git a/mopidy/core.py b/mopidy/core.py index 596e0fe5..9ae461d8 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -22,6 +22,7 @@ from mopidy import (get_version, settings, OptionalDependencyError, SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) from mopidy.gstreamer import GStreamer from mopidy.utils import get_class +from mopidy.utils.deps import list_deps_optparse_callback from mopidy.utils.log import setup_logging from mopidy.utils.path import get_or_create_folder, get_or_create_file from mopidy.utils.process import (exit_handler, stop_remaining_actors, @@ -77,6 +78,9 @@ def parse_options(): parser.add_option('--list-settings', action='callback', callback=list_settings_optparse_callback, help='list current settings') + 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] def check_old_folders(): diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py new file mode 100644 index 00000000..7e6bdc11 --- /dev/null +++ b/mopidy/utils/deps.py @@ -0,0 +1,43 @@ +import sys + +import pykka + + +def list_deps_optparse_callback(*args): + """ + Prints a list of all dependencies. + + Called by optparse when Mopidy is run with the :option:`--list-deps` + option. + """ + print format_dependency_list() + sys.exit(0) + + +def format_dependency_list(adapters=None): + if adapters is None: + adapters = [ + pykka_info, + ] + + lines = [] + for adapter in adapters: + dep_info = adapter() + lines.append('%(name)s: %(version)s' % dep_info) + if 'path' in dep_info: + lines.append(' Imported from: %(path)s' % dep_info) + return '\n'.join(lines) + + +def pykka_info(): + if hasattr(pykka, '__version__'): + # Pykka >= 0.14 + version = pykka.__version__ + else: + # Pykka < 0.14 + version = pykka.get_version() + return { + 'name': 'Pykka', + 'version': version, + 'path': pykka.__file__, + } diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py new file mode 100644 index 00000000..f6d8c942 --- /dev/null +++ b/tests/utils/deps_test.py @@ -0,0 +1,27 @@ +import pykka + +from mopidy.utils import deps + +from tests import unittest + + +class DepsTest(unittest.TestCase): + def test_format_dependency_list(self): + adapters = [ + lambda: dict(name='Python', version='FooPython 2.7.3'), + lambda: dict(name='Platform', version='Loonix 4.0.1'), + lambda: dict(name='Pykka', version='0.1337', path='/foo/bar/baz') + ] + + result = deps.format_dependency_list(adapters) + + self.assertIn('Python: FooPython 2.7.3', result) + self.assertIn('Platform: Loonix 4.0.1', result) + self.assertIn('Imported from: /foo/bar/baz', result) + + def test_pykka_info(self): + result = deps.pykka_info() + + self.assertEquals('Pykka', result['name']) + self.assertEquals(pykka.__version__, result['version']) + self.assertIn('pykka', result['path']) From a25e7d95306a02ab52011cf383a9b28b9c3b39d7 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:14:02 +0200 Subject: [PATCH 02/27] Add pyspotify adapter for --list-deps --- mopidy/utils/deps.py | 27 ++++++++++++++++++++++++++- tests/utils/deps_test.py | 14 +++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 7e6bdc11..febca8dc 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -2,6 +2,8 @@ import sys import pykka +from mopidy.utils.log import indent + def list_deps_optparse_callback(*args): """ @@ -18,14 +20,21 @@ def format_dependency_list(adapters=None): if adapters is None: adapters = [ pykka_info, + pyspotify_info, ] lines = [] for adapter in adapters: dep_info = adapter() - lines.append('%(name)s: %(version)s' % dep_info) + lines.append('%(name)s: %(version)s' % { + 'name': dep_info['name'], + 'version': dep_info.get('version', 'not found'), + }) if 'path' in dep_info: lines.append(' Imported from: %(path)s' % dep_info) + if 'other' in dep_info: + lines.append(' Other: %s' % ( + indent(dep_info['other'])),) return '\n'.join(lines) @@ -41,3 +50,19 @@ def pykka_info(): 'version': version, 'path': pykka.__file__, } + + +def pyspotify_info(): + dep_info = {'name': 'pyspotify'} + try: + import spotify + if hasattr(spotify, '__version__'): + dep_info['version'] = spotify.__version__ + else: + dep_info['version'] = '< 1.3' + dep_info['path'] = spotify.__file__ + dep_info['other'] = 'Built for libspotify API version %d' % ( + spotify.api_version,) + except ImportError: + pass + return dep_info diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index f6d8c942..a2d07b18 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -1,4 +1,5 @@ import pykka +import spotify from mopidy.utils import deps @@ -10,14 +11,16 @@ class DepsTest(unittest.TestCase): adapters = [ lambda: dict(name='Python', version='FooPython 2.7.3'), lambda: dict(name='Platform', version='Loonix 4.0.1'), - lambda: dict(name='Pykka', version='0.1337', path='/foo/bar/baz') + lambda: dict(name='Pykka', path='/foo/bar/baz', other='Quux') ] result = deps.format_dependency_list(adapters) self.assertIn('Python: FooPython 2.7.3', result) self.assertIn('Platform: Loonix 4.0.1', result) + self.assertIn('Pykka: not found', result) self.assertIn('Imported from: /foo/bar/baz', result) + self.assertIn('Quux', result) def test_pykka_info(self): result = deps.pykka_info() @@ -25,3 +28,12 @@ class DepsTest(unittest.TestCase): self.assertEquals('Pykka', result['name']) self.assertEquals(pykka.__version__, result['version']) self.assertIn('pykka', result['path']) + + def test_pyspotify_info(self): + result = deps.pyspotify_info() + + self.assertEquals('pyspotify', result['name']) + self.assertEquals(spotify.__version__, result['version']) + self.assertIn('spotify', result['path']) + self.assertIn('Built for libspotify API version', result['other']) + self.assertIn(str(spotify.api_version), result['other']) From 4c6a6af487c95051be281d2bfc41a758a22acac8 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:40:08 +0200 Subject: [PATCH 03/27] Add Gstreamer adapter for --list-deps --- mopidy/utils/deps.py | 15 +++++++++++++++ tests/utils/deps_test.py | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index febca8dc..1b4d8be8 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -1,5 +1,9 @@ import sys +import pygst +pygst.require('0.10') +import gst + import pykka from mopidy.utils.log import indent @@ -19,6 +23,7 @@ def list_deps_optparse_callback(*args): def format_dependency_list(adapters=None): if adapters is None: adapters = [ + gstreamer_info, pykka_info, pyspotify_info, ] @@ -38,6 +43,16 @@ def format_dependency_list(adapters=None): return '\n'.join(lines) +def gstreamer_info(): + return { + 'name': 'Gstreamer', + 'version': '.'.join(map(str, gst.get_gst_version())), + 'path': gst.__file__, + 'other': 'Python wrapper: gst-python %s' % ( + '.'.join(map(str, gst.get_pygst_version()))), + } + + def pykka_info(): if hasattr(pykka, '__version__'): # Pykka >= 0.14 diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index a2d07b18..acf29b29 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -1,3 +1,7 @@ +import pygst +pygst.require('0.10') +import gst + import pykka import spotify @@ -22,6 +26,15 @@ class DepsTest(unittest.TestCase): self.assertIn('Imported from: /foo/bar/baz', result) self.assertIn('Quux', result) + def test_gstreamer_info(self): + result = deps.gstreamer_info() + + self.assertEquals('Gstreamer', result['name']) + self.assertEquals('.'.join(map(str, gst.get_gst_version())), result['version']) + self.assertIn('gst', result['path']) + self.assertIn('Python wrapper: gst-python', result['other']) + self.assertIn('.'.join(map(str, gst.get_pygst_version())), result['other']) + def test_pykka_info(self): result = deps.pykka_info() From 4284e08d699cdd528d389f56e77d1c37b6bd05cd Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:46:18 +0200 Subject: [PATCH 04/27] Strip file name from printed import paths --- mopidy/utils/deps.py | 4 +++- tests/utils/deps_test.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 1b4d8be8..37f76c27 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -1,3 +1,4 @@ +import os import sys import pygst @@ -36,7 +37,8 @@ def format_dependency_list(adapters=None): 'version': dep_info.get('version', 'not found'), }) if 'path' in dep_info: - lines.append(' Imported from: %(path)s' % dep_info) + lines.append(' Imported from: %s' % ( + os.path.dirname(dep_info['path']))) if 'other' in dep_info: lines.append(' Other: %s' % ( indent(dep_info['other'])),) diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index acf29b29..67ca11ae 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -15,7 +15,7 @@ class DepsTest(unittest.TestCase): adapters = [ lambda: dict(name='Python', version='FooPython 2.7.3'), lambda: dict(name='Platform', version='Loonix 4.0.1'), - lambda: dict(name='Pykka', path='/foo/bar/baz', other='Quux') + lambda: dict(name='Pykka', path='/foo/bar/baz.py', other='Quux') ] result = deps.format_dependency_list(adapters) @@ -23,7 +23,8 @@ class DepsTest(unittest.TestCase): self.assertIn('Python: FooPython 2.7.3', result) self.assertIn('Platform: Loonix 4.0.1', result) self.assertIn('Pykka: not found', result) - self.assertIn('Imported from: /foo/bar/baz', result) + self.assertIn('Imported from: /foo/bar', result) + self.assertNotIn('/baz.py', result) self.assertIn('Quux', result) def test_gstreamer_info(self): From a661b6d8486d1a6b0ba9e9d7e5b6156bde9f86c2 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:49:59 +0200 Subject: [PATCH 05/27] Add pylast adapter for --list-deps --- mopidy/utils/deps.py | 12 ++++++++++++ tests/utils/deps_test.py | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 37f76c27..f72f9cc1 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -27,6 +27,7 @@ def format_dependency_list(adapters=None): gstreamer_info, pykka_info, pyspotify_info, + pylast_info, ] lines = [] @@ -83,3 +84,14 @@ def pyspotify_info(): except ImportError: pass return dep_info + + +def pylast_info(): + dep_info = {'name': 'pylast'} + try: + import pylast + dep_info['version'] = pylast.__version__ + dep_info['path'] = pylast.__file__ + except ImportError: + pass + return dep_info diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 67ca11ae..4df31eef 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -3,6 +3,7 @@ pygst.require('0.10') import gst import pykka +import pylast import spotify from mopidy.utils import deps @@ -51,3 +52,10 @@ class DepsTest(unittest.TestCase): self.assertIn('spotify', result['path']) self.assertIn('Built for libspotify API version', result['other']) self.assertIn(str(spotify.api_version), result['other']) + + def test_pylast_info(self): + result = deps.pylast_info() + + self.assertEquals('pylast', result['name']) + self.assertEquals(pylast.__version__, result['version']) + self.assertIn('pylast', result['path']) From 6e01b320d79c07649e0e501039bd4ee3232dd4d6 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:57:29 +0200 Subject: [PATCH 06/27] Skip tests for unavailable optional deps --- tests/utils/deps_test.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 4df31eef..a0b4fe07 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -1,10 +1,17 @@ import pygst pygst.require('0.10') import gst - import pykka -import pylast -import spotify + +try: + import pylast +except ImportError: + pylast = False + +try: + import spotify +except ImportError: + spotify = False from mopidy.utils import deps @@ -44,6 +51,7 @@ class DepsTest(unittest.TestCase): self.assertEquals(pykka.__version__, result['version']) self.assertIn('pykka', result['path']) + @unittest.skipUnless(spotify, 'pyspotify not found') def test_pyspotify_info(self): result = deps.pyspotify_info() @@ -53,6 +61,7 @@ class DepsTest(unittest.TestCase): self.assertIn('Built for libspotify API version', result['other']) self.assertIn(str(spotify.api_version), result['other']) + @unittest.skipUnless(pylast, 'pylast not found') def test_pylast_info(self): result = deps.pylast_info() From 240ab0d2269b5aba51e4f2d3f6aff8a9f0e652a1 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 22:58:26 +0200 Subject: [PATCH 07/27] Add dbus adapter for --list-deps --- mopidy/utils/deps.py | 12 ++++++++++++ tests/utils/deps_test.py | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index f72f9cc1..ffb69f5b 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -28,6 +28,7 @@ def format_dependency_list(adapters=None): pykka_info, pyspotify_info, pylast_info, + dbus_info, ] lines = [] @@ -95,3 +96,14 @@ def pylast_info(): except ImportError: pass return dep_info + + +def dbus_info(): + dep_info = {'name': 'dbus-python'} + try: + import dbus + dep_info['version'] = dbus.__version__ + dep_info['path'] = dbus.__file__ + except ImportError: + pass + return dep_info diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index a0b4fe07..988e2e84 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -3,6 +3,11 @@ pygst.require('0.10') import gst import pykka +try: + import dbus +except ImportError: + dbus = False + try: import pylast except ImportError: @@ -68,3 +73,11 @@ class DepsTest(unittest.TestCase): self.assertEquals('pylast', result['name']) self.assertEquals(pylast.__version__, result['version']) self.assertIn('pylast', result['path']) + + @unittest.skipUnless(dbus, 'dbus not found') + def test_dbus_info(self): + result = deps.dbus_info() + + self.assertEquals('dbus-python', result['name']) + self.assertEquals(dbus.__version__, result['version']) + self.assertIn('dbus', result['path']) From 44b63070468876486834f539a3b85b4bd1280e11 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 23:13:15 +0200 Subject: [PATCH 08/27] Add pyserial adapter for --list-deps --- mopidy/utils/deps.py | 12 ++++++++++++ tests/utils/deps_test.py | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index ffb69f5b..8403c400 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -29,6 +29,7 @@ def format_dependency_list(adapters=None): pyspotify_info, pylast_info, dbus_info, + serial_info, ] lines = [] @@ -107,3 +108,14 @@ def dbus_info(): except ImportError: pass return dep_info + + +def serial_info(): + dep_info = {'name': 'pyserial'} + try: + import serial + dep_info['version'] = serial.VERSION + dep_info['path'] = serial.__file__ + except ImportError: + pass + return dep_info diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 988e2e84..968d23b0 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -13,6 +13,11 @@ try: except ImportError: pylast = False +try: + import serial +except ImportError: + serial = False + try: import spotify except ImportError: @@ -81,3 +86,11 @@ class DepsTest(unittest.TestCase): self.assertEquals('dbus-python', result['name']) self.assertEquals(dbus.__version__, result['version']) self.assertIn('dbus', result['path']) + + @unittest.skipUnless(serial, 'serial not found') + def test_serial_info(self): + result = deps.serial_info() + + self.assertEquals('pyserial', result['name']) + self.assertEquals(serial.VERSION, result['version']) + self.assertIn('serial', result['path']) From 05c935bc4c24fe8ebb8c6002a67dc33a5171312f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 31 Aug 2012 23:59:53 +0200 Subject: [PATCH 09/27] Add Python impl adapter for --list-deps --- mopidy/utils/deps.py | 11 +++++++++++ tests/utils/deps_test.py | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 8403c400..f0755202 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -1,4 +1,5 @@ import os +import platform import sys import pygst @@ -24,6 +25,7 @@ def list_deps_optparse_callback(*args): def format_dependency_list(adapters=None): if adapters is None: adapters = [ + python_info, gstreamer_info, pykka_info, pyspotify_info, @@ -48,6 +50,15 @@ def format_dependency_list(adapters=None): return '\n'.join(lines) +def python_info(): + return { + 'name': 'Python', + 'version': '%s %s' % (platform.python_implementation(), + platform.python_version()), + 'path': platform.__file__, + } + + def gstreamer_info(): return { 'name': 'Gstreamer', diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 968d23b0..18ec2fe9 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -1,3 +1,5 @@ +import platform + import pygst pygst.require('0.10') import gst @@ -45,6 +47,14 @@ class DepsTest(unittest.TestCase): self.assertNotIn('/baz.py', result) self.assertIn('Quux', result) + def test_python_info(self): + result = deps.python_info() + + self.assertEquals('Python', result['name']) + self.assertIn(platform.python_implementation(), result['version']) + self.assertIn(platform.python_version(), result['version']) + self.assertIn('python', result['path']) + def test_gstreamer_info(self): result = deps.gstreamer_info() From 41853dd3d878b46a617db03f26180f50a20ad1cc Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 00:00:14 +0200 Subject: [PATCH 10/27] Add platform adapter for --list-deps --- mopidy/utils/deps.py | 8 ++++++++ tests/utils/deps_test.py | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index f0755202..f2b89840 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -25,6 +25,7 @@ def list_deps_optparse_callback(*args): def format_dependency_list(adapters=None): if adapters is None: adapters = [ + platform_info, python_info, gstreamer_info, pykka_info, @@ -50,6 +51,13 @@ def format_dependency_list(adapters=None): return '\n'.join(lines) +def platform_info(): + return { + 'name': 'Platform', + 'version': platform.platform(), + } + + def python_info(): return { 'name': 'Python', diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 18ec2fe9..26ef7c5c 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -47,6 +47,12 @@ class DepsTest(unittest.TestCase): self.assertNotIn('/baz.py', result) self.assertIn('Quux', result) + def test_platform_info(self): + result = deps.platform_info() + + self.assertEquals('Platform', result['name']) + self.assertIn(platform.platform(), result['version']) + def test_python_info(self): result = deps.python_info() From d712551c3f346eb17b42e0000c6197d3e340a00c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 00:16:39 +0200 Subject: [PATCH 11/27] Add list of Gstreamer elements to checck in --list-deps --- mopidy/utils/deps.py | 57 ++++++++++++++++++++++++++++++++++++++-- tests/utils/deps_test.py | 1 + 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index f2b89840..13b48dc0 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -68,15 +68,68 @@ def python_info(): def gstreamer_info(): + other = [] + other.append('Python wrapper: gst-python %s' % ( + '.'.join(map(str, gst.get_pygst_version())))) + other.append('Elements:') + for name, status in _gstreamer_check_elements(): + other.append(' %s: %s' % (name, status)) return { 'name': 'Gstreamer', 'version': '.'.join(map(str, gst.get_gst_version())), 'path': gst.__file__, - 'other': 'Python wrapper: gst-python %s' % ( - '.'.join(map(str, gst.get_pygst_version()))), + 'other': '\n'.join(other), } +def _gstreamer_check_elements(): + elements_to_check = [ + # Core playback + 'uridecodebin', + + # External HTTP streams + 'souphttpsrc', + + # Spotify + 'appsrc', + + # Mixers and sinks + 'alsamixer', + 'alsasink', + 'ossmixer', + 'osssink', + 'oss4mixer', + 'oss4sink', + 'pulsemixer', + 'pulsesink', + + # MP3 encoding and decoding + 'mp3parse', + 'mad', + 'id3demux', + 'id3v2mux', + 'lame', + + # Ogg Vorbis encoding and decoding + 'vorbisdec', + 'vorbisenc', + 'vorbisparse', + 'oggdemux', + 'oggmux', + 'oggparse', + + # Flac decoding + 'flacdec', + 'flacparse', + + # Shoutcast output + 'shout2send', + ] + 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] + + def pykka_info(): if hasattr(pykka, '__version__'): # Pykka >= 0.14 diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 26ef7c5c..9c623da0 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -69,6 +69,7 @@ class DepsTest(unittest.TestCase): self.assertIn('gst', result['path']) self.assertIn('Python wrapper: gst-python', result['other']) self.assertIn('.'.join(map(str, gst.get_pygst_version())), result['other']) + self.assertIn('Elements:', result['other']) def test_pykka_info(self): result = deps.pykka_info() From 45086fb11dbe37a1c493b2124147b514a3009d0a Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 00:20:53 +0200 Subject: [PATCH 12/27] Update changelog with --list-deps option (fixes #74) --- docs/changes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changes.rst b/docs/changes.rst index 4dcc8c57..2c697ca4 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -18,6 +18,10 @@ v0.8 (in development) Track position and CPID was intermixed, so it would cause a crash if a CPID matching the track position didn't exist. (Fixes: :issue:`162`) +- Added :option:`--list-deps` option to :cmd:`mopidy` command that lists + required and optional dependencies, their current versions, and some other + information useful for debugging. (Fixes: :issue:`74`) + v0.7.3 (2012-08-11) =================== From a452c49bd3ed4c55658440dc17d58e8f8b1402ce Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 00:49:12 +0200 Subject: [PATCH 13/27] We're only considering a small subset of the Gstreamer elements --- mopidy/utils/deps.py | 2 +- tests/utils/deps_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 13b48dc0..40b53174 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -71,7 +71,7 @@ def gstreamer_info(): other = [] other.append('Python wrapper: gst-python %s' % ( '.'.join(map(str, gst.get_pygst_version())))) - other.append('Elements:') + other.append('Relevant elements:') for name, status in _gstreamer_check_elements(): other.append(' %s: %s' % (name, status)) return { diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 9c623da0..9898b59f 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -69,7 +69,7 @@ class DepsTest(unittest.TestCase): self.assertIn('gst', result['path']) self.assertIn('Python wrapper: gst-python', result['other']) self.assertIn('.'.join(map(str, gst.get_pygst_version())), result['other']) - self.assertIn('Elements:', result['other']) + self.assertIn('Relevant elements:', result['other']) def test_pykka_info(self): result = deps.pykka_info() From f6cea72bf713796c274b9e475305c688adb2f86f Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 00:49:47 +0200 Subject: [PATCH 14/27] Print 'OK' or 'not found' instead of True/False --- mopidy/utils/deps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 40b53174..7fce55db 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -73,7 +73,7 @@ def gstreamer_info(): '.'.join(map(str, gst.get_pygst_version())))) other.append('Relevant elements:') for name, status in _gstreamer_check_elements(): - other.append(' %s: %s' % (name, status)) + other.append(' %s: %s' % (name, 'OK' if status else 'not found')) return { 'name': 'Gstreamer', 'version': '.'.join(map(str, gst.get_gst_version())), From 3c2576a6296c1f80dc97851db93d75554490a9c9 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 11:46:58 +0200 Subject: [PATCH 15/27] Guess what setting you meant based on levenshtein. --- mopidy/utils/settings.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index ff449a61..ce245f3b 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -12,6 +12,7 @@ from mopidy.utils.log import indent logger = logging.getLogger('mopidy.utils.settings') + class SettingsProxy(object): def __init__(self, default_settings_module): self.default = self._get_settings_dict_from_module( @@ -151,11 +152,17 @@ def validate_settings(defaults, settings): u'Available bitrates are 96, 160, and 320.') if setting not in defaults: - errors[setting] = u'Unknown setting. Is it misspelled?' + errors[setting] = u'Unknown setting.' + suggestion = did_you_mean(setting, defaults) + + if suggestion: + errors[setting] += u' Did you mean %s?' % suggestion + continue return errors + def list_settings_optparse_callback(*args): """ Prints a list of all settings. @@ -167,6 +174,7 @@ def list_settings_optparse_callback(*args): print format_settings_list(settings) sys.exit(0) + def format_settings_list(settings): errors = settings.get_errors() lines = [] @@ -181,8 +189,37 @@ def format_settings_list(settings): lines.append(u' Error: %s' % errors[key]) return '\n'.join(lines) + def mask_value_if_secret(key, value): if key.endswith('PASSWORD') and value: return u'********' else: return value + + +def did_you_mean(setting, defaults): + """Suggest most likely setting based on levenshtein.""" + candidates = [(levenshtein(setting, d), d) for d in defaults] + candidates.sort() + + if candidates[0][0] <= 3: + return candidates[0][1] + return None + + +def levenshtein(a, b, max=3): + "Calculates the Levenshtein distance between a and b." + n, m = len(a), len(b) + if n > m: + return levenshtein(b, a) + + 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]: + change = change + 1 + current[j] = min(add, delete, change) + return current[n] From 03a7f03bb8bb808646d6e59b46adbe55eb92fb0c Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 12:11:09 +0200 Subject: [PATCH 16/27] Style fixes to levenshtein and did_you_mean. --- mopidy/utils/settings.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index ce245f3b..4de7d1cf 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -208,18 +208,18 @@ def did_you_mean(setting, defaults): def levenshtein(a, b, max=3): - "Calculates the Levenshtein distance between a and b." + """Calculates the Levenshtein distance between a and b.""" n, m = len(a), len(b) if n > m: return levenshtein(b, a) 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 + 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]: - change = change + 1 + change += 1 current[j] = min(add, delete, change) return current[n] From 4e4a209ec319d20f87d4b7cce6f1a6050b5c8a9e Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 12:15:08 +0200 Subject: [PATCH 17/27] Fix existing settings tests that did_you_mean broke. --- mopidy/utils/settings.py | 3 +++ tests/utils/settings_test.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 4de7d1cf..34126907 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -199,6 +199,9 @@ def mask_value_if_secret(key, value): def did_you_mean(setting, defaults): """Suggest most likely setting based on levenshtein.""" + if not defaults: + return None + candidates = [(levenshtein(setting, d), d) for d in defaults] candidates.sort() diff --git a/tests/utils/settings_test.py b/tests/utils/settings_test.py index 55e1156b..c129b9b5 100644 --- a/tests/utils/settings_test.py +++ b/tests/utils/settings_test.py @@ -23,7 +23,7 @@ class ValidateSettingsTest(unittest.TestCase): result = validate_settings(self.defaults, {'MPD_SERVER_HOSTNMAE': '127.0.0.1'}) self.assertEqual(result['MPD_SERVER_HOSTNMAE'], - u'Unknown setting. Is it misspelled?') + u'Unknown setting. Did you mean MPD_SERVER_HOSTNAME?') def test_not_renamed_setting_returns_error(self): result = validate_settings(self.defaults, From 1f8289a25616a2d15e21d54119297aba2ebb66d2 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 12:22:41 +0200 Subject: [PATCH 18/27] Switch to only importing modules in settings_test. --- tests/utils/settings_test.py | 47 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/tests/utils/settings_test.py b/tests/utils/settings_test.py index c129b9b5..1b0c4a2a 100644 --- a/tests/utils/settings_test.py +++ b/tests/utils/settings_test.py @@ -1,8 +1,7 @@ import os -from mopidy import settings as default_settings_module, SettingsError -from mopidy.utils.settings import (format_settings_list, mask_value_if_secret, - SettingsProxy, validate_settings) +import mopidy +from mopidy.utils import settings as setting_utils from tests import unittest @@ -16,29 +15,29 @@ class ValidateSettingsTest(unittest.TestCase): } def test_no_errors_yields_empty_dict(self): - result = validate_settings(self.defaults, {}) + result = setting_utils.validate_settings(self.defaults, {}) self.assertEqual(result, {}) def test_unknown_setting_returns_error(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'MPD_SERVER_HOSTNMAE': '127.0.0.1'}) self.assertEqual(result['MPD_SERVER_HOSTNMAE'], u'Unknown setting. Did you mean MPD_SERVER_HOSTNAME?') def test_not_renamed_setting_returns_error(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'SERVER_HOSTNAME': '127.0.0.1'}) self.assertEqual(result['SERVER_HOSTNAME'], u'Deprecated setting. Use MPD_SERVER_HOSTNAME.') def test_unneeded_settings_returns_error(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'SPOTIFY_LIB_APPKEY': '/tmp/foo'}) self.assertEqual(result['SPOTIFY_LIB_APPKEY'], u'Deprecated setting. It may be removed.') def test_deprecated_setting_value_returns_error(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'BACKENDS': ('mopidy.backends.despotify.DespotifyBackend',)}) self.assertEqual(result['BACKENDS'], u'Deprecated setting value. ' + @@ -46,33 +45,33 @@ class ValidateSettingsTest(unittest.TestCase): 'available.') def test_unavailable_bitrate_setting_returns_error(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'SPOTIFY_BITRATE': 50}) self.assertEqual(result['SPOTIFY_BITRATE'], u'Unavailable Spotify bitrate. ' + u'Available bitrates are 96, 160, and 320.') def test_two_errors_are_both_reported(self): - result = validate_settings(self.defaults, + result = setting_utils.validate_settings(self.defaults, {'FOO': '', 'BAR': ''}) self.assertEqual(len(result), 2) def test_masks_value_if_secret(self): - secret = mask_value_if_secret('SPOTIFY_PASSWORD', 'bar') + secret = setting_utils.mask_value_if_secret('SPOTIFY_PASSWORD', 'bar') self.assertEqual(u'********', secret) def test_does_not_mask_value_if_not_secret(self): - not_secret = mask_value_if_secret('SPOTIFY_USERNAME', 'foo') + not_secret = setting_utils.mask_value_if_secret('SPOTIFY_USERNAME', 'foo') self.assertEqual('foo', not_secret) def test_does_not_mask_value_if_none(self): - not_secret = mask_value_if_secret('SPOTIFY_USERNAME', None) + not_secret = setting_utils.mask_value_if_secret('SPOTIFY_USERNAME', None) self.assertEqual(None, not_secret) class SettingsProxyTest(unittest.TestCase): def setUp(self): - self.settings = SettingsProxy(default_settings_module) + self.settings = setting_utils.SettingsProxy(mopidy.settings) self.settings.local.clear() def test_set_and_get_attr(self): @@ -83,7 +82,7 @@ class SettingsProxyTest(unittest.TestCase): try: _ = self.settings.TEST self.fail(u'Should raise exception') - except SettingsError as e: + except mopidy.SettingsError as e: self.assertEqual(u'Setting "TEST" is not set.', e.message) def test_getattr_raises_error_on_empty_setting(self): @@ -91,7 +90,7 @@ class SettingsProxyTest(unittest.TestCase): try: _ = self.settings.TEST self.fail(u'Should raise exception') - except SettingsError as e: + except mopidy.SettingsError as e: self.assertEqual(u'Setting "TEST" is empty.', e.message) def test_getattr_does_not_raise_error_if_setting_is_false(self): @@ -177,44 +176,44 @@ class SettingsProxyTest(unittest.TestCase): class FormatSettingListTest(unittest.TestCase): def setUp(self): - self.settings = SettingsProxy(default_settings_module) + self.settings = setting_utils.SettingsProxy(mopidy.settings) def test_contains_the_setting_name(self): self.settings.TEST = u'test' - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_('TEST:' in result, result) def test_repr_of_a_string_value(self): self.settings.TEST = u'test' - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("TEST: u'test'" in result, result) def test_repr_of_an_int_value(self): self.settings.TEST = 123 - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("TEST: 123" in result, result) def test_repr_of_a_tuple_value(self): self.settings.TEST = (123, u'abc') - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("TEST: (123, u'abc')" in result, result) def test_passwords_are_masked(self): self.settings.TEST_PASSWORD = u'secret' - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("TEST_PASSWORD: u'secret'" not in result, result) self.assert_("TEST_PASSWORD: u'********'" in result, result) def test_short_values_are_not_pretty_printed(self): self.settings.FRONTEND = (u'mopidy.frontends.mpd.MpdFrontend',) - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("FRONTEND: (u'mopidy.frontends.mpd.MpdFrontend',)" in result, result) def test_long_values_are_pretty_printed(self): self.settings.FRONTEND = (u'mopidy.frontends.mpd.MpdFrontend', u'mopidy.frontends.lastfm.LastfmFrontend') - result = format_settings_list(self.settings) + result = setting_utils.format_settings_list(self.settings) self.assert_("""FRONTEND: (u'mopidy.frontends.mpd.MpdFrontend', u'mopidy.frontends.lastfm.LastfmFrontend')""" in result, result) From e4d425d37aed3ab8a1a7c7b3c1428bb7bf4c03a8 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 12:28:32 +0200 Subject: [PATCH 19/27] Add did you mean tests for settings. - Checks varying degrees of typos until the edit distance becomes to large. - Also updated did you mean to always uppercase it's input so we catch caps errors. --- mopidy/utils/settings.py | 1 + tests/utils/settings_test.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 34126907..4072f24d 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -202,6 +202,7 @@ def did_you_mean(setting, defaults): if not defaults: return None + setting = setting.upper() candidates = [(levenshtein(setting, d), d) for d in defaults] candidates.sort() diff --git a/tests/utils/settings_test.py b/tests/utils/settings_test.py index 1b0c4a2a..7d104969 100644 --- a/tests/utils/settings_test.py +++ b/tests/utils/settings_test.py @@ -217,3 +217,27 @@ class FormatSettingListTest(unittest.TestCase): self.assert_("""FRONTEND: (u'mopidy.frontends.mpd.MpdFrontend', u'mopidy.frontends.lastfm.LastfmFrontend')""" in result, result) + + +class DidYouMeanTest(unittest.TestCase): + def testSuggestoins(self): + defaults = { + 'MPD_SERVER_HOSTNAME': '::', + 'MPD_SERVER_PORT': 6600, + 'SPOTIFY_BITRATE': 160, + } + + suggestion = setting_utils.did_you_mean('spotify_bitrate', defaults) + self.assertEqual(suggestion, 'SPOTIFY_BITRATE') + + suggestion = setting_utils.did_you_mean('SPOTIFY_BITROTE', defaults) + self.assertEqual(suggestion, 'SPOTIFY_BITRATE') + + suggestion = setting_utils.did_you_mean('SPITIFY_BITROT', defaults) + self.assertEqual(suggestion, 'SPOTIFY_BITRATE') + + suggestion = setting_utils.did_you_mean('SPTIFY_BITROT', defaults) + self.assertEqual(suggestion, 'SPOTIFY_BITRATE') + + suggestion = setting_utils.did_you_mean('SPTIFY_BITRO', defaults) + self.assertEqual(suggestion, None) From 5c6dc96f9dd4bcc5c3b72776c4b0b5b560748f94 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 13:07:14 +0200 Subject: [PATCH 20/27] Fix typo --- mopidy/utils/deps.py | 2 +- tests/utils/deps_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/utils/deps.py b/mopidy/utils/deps.py index 7fce55db..2c68e429 100644 --- a/mopidy/utils/deps.py +++ b/mopidy/utils/deps.py @@ -75,7 +75,7 @@ def gstreamer_info(): for name, status in _gstreamer_check_elements(): other.append(' %s: %s' % (name, 'OK' if status else 'not found')) return { - 'name': 'Gstreamer', + 'name': 'GStreamer', 'version': '.'.join(map(str, gst.get_gst_version())), 'path': gst.__file__, 'other': '\n'.join(other), diff --git a/tests/utils/deps_test.py b/tests/utils/deps_test.py index 9898b59f..f5aa0b1e 100644 --- a/tests/utils/deps_test.py +++ b/tests/utils/deps_test.py @@ -64,7 +64,7 @@ class DepsTest(unittest.TestCase): def test_gstreamer_info(self): result = deps.gstreamer_info() - self.assertEquals('Gstreamer', result['name']) + self.assertEquals('GStreamer', result['name']) self.assertEquals('.'.join(map(str, gst.get_gst_version())), result['version']) self.assertIn('gst', result['path']) self.assertIn('Python wrapper: gst-python', result['other']) From 1c77f9178b56b7e25de24b4ceef9a64b416a9886 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sat, 1 Sep 2012 13:33:06 +0200 Subject: [PATCH 21/27] Update changelog with did-you-mean setting matching --- docs/changes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changes.rst b/docs/changes.rst index 2c697ca4..8c7e9d1d 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -22,6 +22,10 @@ v0.8 (in development) required and optional dependencies, their current versions, and some other information useful for debugging. (Fixes: :issue:`74`) +- When unknown settings are encountered, we now check if it's similar to a + known setting, and suggests to the user what we think the setting should have + been. + v0.7.3 (2012-08-11) =================== From 09b02f055859e003c121a1852a448934d8b99cc0 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 3 Sep 2012 16:09:14 +0200 Subject: [PATCH 22/27] Reraise exception without losing the traceback (fixes #173) --- mopidy/frontends/mpd/protocol/music_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/frontends/mpd/protocol/music_db.py b/mopidy/frontends/mpd/protocol/music_db.py index cde2754a..da8de91e 100644 --- a/mopidy/frontends/mpd/protocol/music_db.py +++ b/mopidy/frontends/mpd/protocol/music_db.py @@ -196,7 +196,7 @@ def _list_build_query(field, mpd_query): if error.message == 'No closing quotation': raise MpdArgError(u'Invalid unquoted character', command=u'list') else: - raise error + raise tokens = [t.decode('utf-8') for t in tokens] if len(tokens) == 1: if field == u'album': From 763d09b17263a58735a394ec6bd7e3a879c4cf60 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 3 Sep 2012 22:15:43 +0200 Subject: [PATCH 23/27] Tweak OUTPUT docs --- docs/changes.rst | 10 +++++----- docs/settings.rst | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index ce01c364..ce011d9b 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -26,11 +26,11 @@ v0.8 (in development) known setting, and suggests to the user what we think the setting should have been. -- Removed most traces of multiple outputs support. Having this feature - currently seems to be more trouble than what it is worth. - :attr:`mopidy.settings.OUTPUTS` setting is no longer supported, and has been - replaced with :attr:`mopidy.settings.OUTPUT` which is a GStreamer - bin described in the same format as ``gst-launch`` expects. Default value is +- Removed multiple outputs support. Having this feature currently seems to be + more trouble than what it is worth. The :attr:`mopidy.settings.OUTPUTS` + setting is no longer supported, and has been replaced with + :attr:`mopidy.settings.OUTPUT` which is a GStreamer bin description string in + the same format as ``gst-launch`` expects. Default value is ``autoaudiosink``. diff --git a/docs/settings.rst b/docs/settings.rst index 2f0f0f12..94f3c63b 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -157,13 +157,13 @@ server simultaneously. To use the SHOUTcast output, do the following: #. Install, configure and start the Icecast server. It can be found in the ``icecast2`` package in Debian/Ubuntu. -#. Set :attr:`mopidy.settings.OUTPUT` to ``lame ! shout2send`` (an Ogg Vorbis - encoder could be used instead of lame). +#. Set :attr:`mopidy.settings.OUTPUT` to ``lame ! shout2send``. An Ogg Vorbis + encoder could be used instead of the lame MP3 encoder. #. You might also need to change the ``shout2send`` default settings, run ``gst-inspect-0.10 shout2send`` to see the available settings. Most likely - you want to change ``ip``, ``username``, ``password`` and ``mount``. For - example, to set the password use: + you want to change ``ip``, ``username``, ``password``, and ``mount``. For + example, to set the username and password, use: ``lame ! shout2send username="foobar" password="s3cret"``. Other advanced setups are also possible for outputs. Basically anything you can From 7866d6230024d50c8dbf7d7ce286515dfb9b6f21 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 3 Sep 2012 22:32:19 +0200 Subject: [PATCH 24/27] Improve docstring --- mopidy/utils/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index 55bf43d0..d369fa44 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -102,7 +102,7 @@ def validate_settings(defaults, settings): Checks the settings for both errors like misspellings and against a set of rules for renamed settings, etc. - Returns of setting names with associated errors. + Returns mapping from setting names to associated errors. :param defaults: Mopidy's default settings :type defaults: dict From 252984138f1207a5713f3b8dbbce2e3f79415f3d Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 3 Sep 2012 22:32:44 +0200 Subject: [PATCH 25/27] Map old settings GSTREAMER_AUDIO_SINK and LOCAL_OUTPUT_OVERRIDE to the new OUTPUT setting --- mopidy/utils/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index d369fa44..aa6dd3ae 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -117,9 +117,9 @@ def validate_settings(defaults, settings): 'DUMP_LOG_FILENAME': 'DEBUG_LOG_FILENAME', 'DUMP_LOG_FORMAT': 'DEBUG_LOG_FORMAT', 'FRONTEND': 'FRONTENDS', - 'GSTREAMER_AUDIO_SINK': 'CUSTOM_OUTPUT', + 'GSTREAMER_AUDIO_SINK': 'OUTPUT', 'LOCAL_MUSIC_FOLDER': 'LOCAL_MUSIC_PATH', - 'LOCAL_OUTPUT_OVERRIDE': 'CUSTOM_OUTPUT', + 'LOCAL_OUTPUT_OVERRIDE': 'OUTPUT', 'LOCAL_PLAYLIST_FOLDER': 'LOCAL_PLAYLIST_PATH', 'LOCAL_TAG_CACHE': 'LOCAL_TAG_CACHE_FILE', 'SERVER': None, From 5f8374a174b286c51446b94177fd3da65383cdd0 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Mon, 3 Sep 2012 22:32:57 +0200 Subject: [PATCH 26/27] Use same wording in setting validation and docs --- mopidy/utils/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index aa6dd3ae..ec58bab3 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -148,7 +148,7 @@ def validate_settings(defaults, settings): elif setting == 'OUTPUTS': errors[setting] = ( u'Deprecated setting, please change to OUTPUT. OUTPUT expectes ' - u'a GStreamer bin describing your desired output.') + u'a GStreamer bin description string for your desired output.') elif setting == 'SPOTIFY_BITRATE': if value not in (96, 160, 320): From ceda42151037c20571635e7bd3f8c1ee89d1ecd9 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Sat, 1 Sep 2012 15:59:38 +0200 Subject: [PATCH 27/27] Cleanup error handling of bad GStreamer settings. No need to have a GStreamerError, we can just let the GErrors bubble now that we are initialising in the main thread. Conflicts: mopidy/gstreamer.py --- mopidy/core.py | 4 +--- mopidy/gstreamer.py | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index 6e6972f5..9ae461d8 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -20,7 +20,7 @@ sys.argv[1:] = gstreamer_args from mopidy import (get_version, settings, OptionalDependencyError, SettingsError, DATA_PATH, SETTINGS_PATH, SETTINGS_FILE) -from mopidy.gstreamer import GStreamer, GStreamerError +from mopidy.gstreamer import GStreamer from mopidy.utils import get_class from mopidy.utils.deps import list_deps_optparse_callback from mopidy.utils.log import setup_logging @@ -46,8 +46,6 @@ def main(): loop.run() except SettingsError as e: logger.error(e.message) - except GStreamerError as e: - logger.error(e) except KeyboardInterrupt: logger.info(u'Interrupted. Exiting...') except Exception as e: diff --git a/mopidy/gstreamer.py b/mopidy/gstreamer.py index ab4fd59b..866c8868 100644 --- a/mopidy/gstreamer.py +++ b/mopidy/gstreamer.py @@ -11,13 +11,10 @@ from pykka.registry import ActorRegistry from mopidy import settings from mopidy.backends.base import Backend + logger = logging.getLogger('mopidy.gstreamer') -class GStreamerError(Exception): - pass - - class GStreamer(ThreadingActor): """ Audio output through `GStreamer `_.