From 12e5bc39e310f247f74aa3312610e9600857223c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Tue, 17 Aug 2010 01:45:52 +0200 Subject: [PATCH] Add settings validation --- docs/changes.rst | 2 ++ mopidy/__init__.py | 1 + mopidy/utils/settings.py | 57 ++++++++++++++++++++++++++++++++++++ tests/utils/settings_test.py | 40 +++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 tests/utils/settings_test.py diff --git a/docs/changes.rst b/docs/changes.rst index 323f899e..9f5efa84 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -31,6 +31,8 @@ greatly improved MPD client support. **Changes** - Exit early if not Python >= 2.6, < 3. +- Validate settings at startup and print useful error messages if the settings + has not been updated or anything is misspelled. - Include Sphinx scripts for building docs, pylintrc, tests and test data in the packages created by ``setup.py`` for i.e. PyPI. - MPD frontend: diff --git a/mopidy/__init__.py b/mopidy/__init__.py index e3321041..9faf31cb 100644 --- a/mopidy/__init__.py +++ b/mopidy/__init__.py @@ -28,3 +28,4 @@ class SettingsError(MopidyException): from mopidy import settings as default_settings_module from mopidy.utils.settings import SettingsProxy settings = SettingsProxy(default_settings_module) +settings.validate() diff --git a/mopidy/utils/settings.py b/mopidy/utils/settings.py index f7209653..d06e822a 100644 --- a/mopidy/utils/settings.py +++ b/mopidy/utils/settings.py @@ -1,6 +1,7 @@ # Absolute import needed to import ~/.mopidy/settings.py and not ourselves from __future__ import absolute_import from copy import copy +import logging import os import sys @@ -40,3 +41,59 @@ class SettingsProxy(object): raise SettingsError(u'Setting "%s" is empty.' % attr) return value + def validate(self): + if self.get_errors(): + sys.exit(self.get_errors_as_string()) + + def get_errors(self): + return validate_settings(self.default_settings, self.local_settings) + + def get_errors_as_string(self): + lines = [u'Errors:'] + for (setting, error) in self.get_errors().iteritems(): + lines.append(u' %s: %s' % (setting, error)) + return '\n'.join(lines) + + +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. + + :param defaults: Mopidy's default settings + :type defaults: dict + :param settings: the user's local settings + :type settings: dict + :rtype: dict + """ + errors = {} + + changed = { + 'SERVER_HOSTNAME': 'MPD_SERVER_HOSTNAME', + 'SERVER_PORT': 'MPD_SERVER_PORT', + 'SPOTIFY_LIB_APPKEY': None, + } + + for setting, value in settings.iteritems(): + if setting in changed: + if changed[setting] is None: + errors[setting] = u'Deprecated setting. It may be removed.' + else: + errors[setting] = u'Deprecated setting. Use %s.' % ( + changed[setting],) + break + + if setting == 'BACKENDS': + if 'mopidy.backends.despotify.DespotifyBackend' in value: + errors[setting] = (u'Deprecated setting value. ' + + '"mopidy.backends.despotify.DespotifyBackend" is no ' + + 'longer available.') + break + + if setting not in defaults: + errors[setting] = u'Unknown setting. Is it misspelled?' + break + + return errors diff --git a/tests/utils/settings_test.py b/tests/utils/settings_test.py new file mode 100644 index 00000000..0e1076c9 --- /dev/null +++ b/tests/utils/settings_test.py @@ -0,0 +1,40 @@ +import unittest + +from mopidy.utils.settings import validate_settings + +class ValidateSettingsTest(unittest.TestCase): + def setUp(self): + self.defaults = { + 'MPD_SERVER_HOSTNAME': '::', + 'MPD_SERVER_PORT': 6600, + } + + def test_no_errors_yields_empty_dict(self): + result = validate_settings(self.defaults, {}) + self.assertEqual(result, {}) + + def test_unknown_setting_returns_error(self): + result = validate_settings(self.defaults, + {'MPD_SERVER_HOSTNMAE': '127.0.0.1'}) + self.assertEqual(result['MPD_SERVER_HOSTNMAE'], + u'Unknown setting. Is it misspelled?') + + def test_not_renamed_setting_returns_error(self): + result = 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, + {'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, + {'BACKENDS': ('mopidy.backends.despotify.DespotifyBackend',)}) + self.assertEqual(result['BACKENDS'], + u'Deprecated setting value. ' + + '"mopidy.backends.despotify.DespotifyBackend" is no longer ' + + 'available.')