diff --git a/mopidy/__main__.py b/mopidy/__main__.py index a9649bd1..8f98de5c 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -53,7 +53,7 @@ def main(): raw_config = config_lib.load(config_files, config_overrides, extensions) extensions = ext.filter_enabled_extensions(raw_config, extensions) config = config_lib.validate( - raw_config, config_lib.config_schemas, extensions) + raw_config, config_lib.core_schemas, extensions) log.setup_log_levels(config) check_old_locations() @@ -139,23 +139,24 @@ def show_config_callback(option, opt, value, parser): raw_config = config_lib.load(files, overrides, extensions) enabled_extensions = ext.filter_enabled_extensions(raw_config, extensions) config = config_lib.validate( - raw_config, config_lib.config_schemas, enabled_extensions) + raw_config, config_lib.core_schemas, enabled_extensions) # TODO: create mopidy.config.format? output = [] - for section_name, schema in config_lib.config_schemas.items(): - options = config.get(section_name, {}) + for schema in config_lib.core_schemas: + options = config.get(schema.name, {}) if not options: continue - output.append(schema.format(section_name, options)) + output.append(schema.format(options)) for extension in extensions: + schema = extension.get_config_schema() + if extension in enabled_extensions: - schema = extension.get_config_schema() - options = config.get(extension.ext_name, {}) - output.append(schema.format(extension.ext_name, options)) + options = config.get(schema.name, {}) + output.append(schema.format(options)) else: - lines = ['[%s]' % extension.ext_name, 'enabled = false', + lines = ['[%s]' % schema.name, 'enabled = false', '# Config hidden as extension is disabled'] output.append('\n'.join(lines)) diff --git a/mopidy/config/__init__.py b/mopidy/config/__init__.py index 48334942..a8ece9c1 100644 --- a/mopidy/config/__init__.py +++ b/mopidy/config/__init__.py @@ -13,26 +13,27 @@ from mopidy.utils import path logger = logging.getLogger('mopdiy.config') -config_schemas = {} # TODO: use ordered dict or list? -config_schemas['logging'] = ConfigSchema() -config_schemas['logging']['console_format'] = String() -config_schemas['logging']['debug_format'] = String() -config_schemas['logging']['debug_file'] = Path() +_logging_schema = ConfigSchema('logging') +_logging_schema['console_format'] = String() +_logging_schema['debug_format'] = String() +_logging_schema['debug_file'] = Path() -config_schemas['logging.levels'] = LogLevelConfigSchema() +_loglevels_schema = LogLevelConfigSchema('logging.levels') -config_schemas['audio'] = ConfigSchema() -config_schemas['audio']['mixer'] = String() -config_schemas['audio']['mixer_track'] = String(optional=True) -config_schemas['audio']['output'] = String() +_audio_schema = ConfigSchema('audio') +_audio_schema['mixer'] = String() +_audio_schema['mixer_track'] = String(optional=True) +_audio_schema['output'] = String() -config_schemas['proxy'] = ConfigSchema() -config_schemas['proxy']['hostname'] = Hostname(optional=True) -config_schemas['proxy']['username'] = String(optional=True) -config_schemas['proxy']['password'] = String(optional=True, secret=True) +_proxy_schema = ConfigSchema('proxy') +_proxy_schema['hostname'] = Hostname(optional=True) +_proxy_schema['username'] = String(optional=True) +_proxy_schema['password'] = String(optional=True, secret=True) # NOTE: if multiple outputs ever comes something like LogLevelConfigSchema -#config_schemas['audio.outputs'] = config.AudioOutputConfigSchema() +#_outputs_schema = config.AudioOutputConfigSchema() + +core_schemas = [_logging_schema, _loglevels_schema, _audio_schema, _proxy_schema] def read(config_file): @@ -85,12 +86,8 @@ def _load(files, defaults, overrides): def validate(raw_config, schemas, extensions=None): # Collect config schemas to validate against - sections_and_schemas = schemas.items() - for extension in extensions or []: - sections_and_schemas.append( - (extension.ext_name, extension.get_config_schema())) - - config, errors = _validate(raw_config, sections_and_schemas) + extension_schemas = [e.get_config_schema() for e in extensions or []] + config, errors = _validate(raw_config, schemas + extension_schemas) if errors: # TODO: raise error instead. @@ -107,10 +104,10 @@ def _validate(raw_config, schemas): # Get validated config config = {} errors = [] - for name, schema in schemas: + for schema in schemas: try: - items = raw_config[name].items() - config[name] = schema.convert(items) + items = raw_config[schema.name].items() + config[schema.name] = schema.convert(items) except KeyError: errors.append('%s: section not found.' % name) except exceptions.ConfigError as error: diff --git a/mopidy/config/schemas.py b/mopidy/config/schemas.py index b074e79a..19b5d665 100644 --- a/mopidy/config/schemas.py +++ b/mopidy/config/schemas.py @@ -45,7 +45,8 @@ class ConfigSchema(object): :meth:`format` method that can used for printing out the converted values. """ # TODO: Use collections.OrderedDict once 2.6 support is gone (#344) - def __init__(self): + def __init__(self, name): + self.name = name self._schema = {} self._order = [] @@ -57,10 +58,10 @@ class ConfigSchema(object): def __getitem__(self, key): return self._schema[key] - def format(self, name, values): + def format(self, values): # TODO: should the output be encoded utf-8 since we use that in # serialize for strings? - lines = ['[%s]' % name] + lines = ['[%s]' % self.name] for key in self._order: value = values.get(key) if value is not None: @@ -97,8 +98,8 @@ class ExtensionConfigSchema(ConfigSchema): Ensures that ``enabled`` config value is present. """ - def __init__(self): - super(ExtensionConfigSchema, self).__init__() + def __init__(self, name): + super(ExtensionConfigSchema, self).__init__(name) self['enabled'] = types.Boolean() @@ -109,11 +110,12 @@ class LogLevelConfigSchema(object): as understood by the :class:`LogLevel` config value. Does not sub-class :class:`ConfigSchema`, but implements the same interface. """ - def __init__(self): + def __init__(self, name): + self.name = name self._config_value = types.LogLevel() - def format(self, name, values): - lines = ['[%s]' % name] + def format(self, values): + lines = ['[%s]' % self.name] for key, value in sorted(values.items()): if value is not None: lines.append('%s = %s' % ( diff --git a/mopidy/ext.py b/mopidy/ext.py index c90e75e3..aa8ec5e0 100644 --- a/mopidy/ext.py +++ b/mopidy/ext.py @@ -24,7 +24,7 @@ class Extension(object): def get_config_schema(self): """TODO""" - return config_lib.ExtensionConfigSchema() + return config_lib.ExtensionConfigSchema(self.ext_name) def validate_environment(self): """TODO""" diff --git a/tests/config/config_test.py b/tests/config/config_test.py index 00cb4e83..dc1b1c59 100644 --- a/tests/config/config_test.py +++ b/tests/config/config_test.py @@ -52,6 +52,10 @@ class LoadConfigTest(unittest.TestCase): class ValidateTest(unittest.TestCase): + def setUp(self): + self.schema = mock.Mock() + self.schema.name = 'foo' + def test_empty_config_no_schemas(self): conf, errors = config._validate({}, []) self.assertEqual({}, conf) @@ -64,23 +68,21 @@ class ValidateTest(unittest.TestCase): self.assertEqual([], errors) def test_empty_config_single_schema(self): - conf, errors = config._validate({}, [('foo', mock.Mock())]) + conf, errors = config._validate({}, [self.schema]) self.assertEqual({}, conf) self.assertEqual(['foo: section not found.'], errors) def test_config_single_schema(self): raw_config = {'foo': {'bar': 'baz'}} - schema = mock.Mock() - schema.convert.return_value = {'baz': 'bar'} - conf, errors = config._validate(raw_config, [('foo', schema)]) + self.schema.convert.return_value = {'baz': 'bar'} + conf, errors = config._validate(raw_config, [self.schema]) self.assertEqual({'foo': {'baz': 'bar'}}, conf) self.assertEqual([], errors) def test_config_single_schema_config_error(self): raw_config = {'foo': {'bar': 'baz'}} - schema = mock.Mock() - schema.convert.side_effect = exceptions.ConfigError({'bar': 'bad'}) - conf, errors = config._validate(raw_config, [('foo', schema)]) + self.schema.convert.side_effect = exceptions.ConfigError({'bar': 'bad'}) + conf, errors = config._validate(raw_config, [self.schema]) self.assertEqual(['foo/bar: bad'], errors) self.assertEqual({}, conf) diff --git a/tests/config/schemas_test.py b/tests/config/schemas_test.py index e7d6dde1..487136c2 100644 --- a/tests/config/schemas_test.py +++ b/tests/config/schemas_test.py @@ -11,7 +11,7 @@ from tests import unittest class ConfigSchemaTest(unittest.TestCase): def setUp(self): - self.schema = schemas.ConfigSchema() + self.schema = schemas.ConfigSchema('test') self.schema['foo'] = mock.Mock() self.schema['bar'] = mock.Mock() self.schema['baz'] = mock.Mock() @@ -22,8 +22,8 @@ class ConfigSchemaTest(unittest.TestCase): self.schema['bar'].format.return_value = 'asd' self.schema['baz'].format.return_value = 'zxc' - expected = ['[qwerty]', 'foo = qwe', 'bar = asd', 'baz = zxc'] - result = self.schema.format('qwerty', self.values) + expected = ['[test]', 'foo = qwe', 'bar = asd', 'baz = zxc'] + result = self.schema.format(self.values) self.assertEqual('\n'.join(expected), result) def test_format_unkwown_value(self): @@ -32,7 +32,7 @@ class ConfigSchemaTest(unittest.TestCase): self.schema['baz'].format.return_value = 'zxc' self.values['unknown'] = 'rty' - result = self.schema.format('qwerty', self.values) + result = self.schema.format(self.values) self.assertNotIn('unknown = rty', result) def test_convert(self): @@ -88,7 +88,7 @@ class ConfigSchemaTest(unittest.TestCase): class ExtensionConfigSchemaTest(unittest.TestCase): def test_schema_includes_enabled(self): - schema = schemas.ExtensionConfigSchema() + schema = schemas.ExtensionConfigSchema('test') self.assertIsInstance(schema['enabled'], types.Boolean) @@ -101,10 +101,10 @@ class LogLevelConfigSchemaTest(unittest.TestCase): self.assertEqual(logging.INFO, result['baz']) def test_format(self): - schema = schemas.LogLevelConfigSchema() + schema = schemas.LogLevelConfigSchema('test') values = {'foo.bar': logging.DEBUG, 'baz': logging.INFO} - expected = ['[levels]', 'baz = info', 'foo.bar = debug'] - result = schema.format('levels', values) + expected = ['[test]', 'baz = info', 'foo.bar = debug'] + result = schema.format(values) self.assertEqual('\n'.join(expected), result)