Merge pull request #1232 from dprokic/feature/843-core-config-for-data-config-cache-dirs
config: Add config for data/config/cache directories
This commit is contained in:
commit
0dc47e6084
@ -61,6 +61,18 @@ Mopidy's core has the following configuration values that you can change.
|
||||
Core configuration
|
||||
------------------
|
||||
|
||||
.. confval:: core/cache_dir
|
||||
|
||||
Path to directory for storing cached information.
|
||||
|
||||
.. confval:: core/config_dir
|
||||
|
||||
Path to directory with configuration files.
|
||||
|
||||
.. confval:: core/data_dir
|
||||
|
||||
Path to directory with data files.
|
||||
|
||||
.. confval:: core/max_tracklist_length
|
||||
|
||||
Max length of the tracklist. Defaults to 10000.
|
||||
|
||||
@ -16,6 +16,9 @@ from mopidy.internal import path, versioning
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_core_schema = ConfigSchema('core')
|
||||
_core_schema['cache_dir'] = Path()
|
||||
_core_schema['config_dir'] = Path()
|
||||
_core_schema['data_dir'] = Path()
|
||||
# MPD supports at most 10k tracks, some clients segfault when this is exceeded.
|
||||
_core_schema['max_tracklist_length'] = Integer(minimum=1, maximum=10000)
|
||||
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
[core]
|
||||
cache_dir = $XDG_CACHE_DIR/mopidy
|
||||
config_dir = $XDG_CONFIG_DIR/mopidy
|
||||
data_dir = $XDG_DATA_DIR/mopidy
|
||||
max_tracklist_length = 10000
|
||||
|
||||
[logging]
|
||||
|
||||
@ -2,10 +2,12 @@ from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
|
||||
from mopidy import config as config_lib, exceptions
|
||||
from mopidy.internal import path
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -58,6 +60,42 @@ class Extension(object):
|
||||
schema['enabled'] = config_lib.Boolean()
|
||||
return schema
|
||||
|
||||
def get_cache_dir(self, config):
|
||||
"""Get or create cache directory for extension and return path
|
||||
|
||||
:param config: Loaded configuration
|
||||
:return: string
|
||||
"""
|
||||
assert self.ext_name is not None
|
||||
cache_dir_path = bytes(os.path.join(config['core']['cache_dir'],
|
||||
self.ext_name))
|
||||
path.get_or_create_dir(cache_dir_path)
|
||||
return cache_dir_path
|
||||
|
||||
def get_config_dir(self, config):
|
||||
"""Get or create configuration directory for extension and return path
|
||||
|
||||
:param config: Loaded configuration
|
||||
:return: string
|
||||
"""
|
||||
assert self.ext_name is not None
|
||||
config_dir_path = bytes(os.path.join(config['core']['config_dir'],
|
||||
self.ext_name))
|
||||
path.get_or_create_dir(config_dir_path)
|
||||
return config_dir_path
|
||||
|
||||
def get_data_dir(self, config):
|
||||
"""Get or create data directory for extension and return path
|
||||
|
||||
:param config: Loaded configuration
|
||||
:returns: string
|
||||
"""
|
||||
assert self.ext_name is not None
|
||||
data_dir_path = bytes(os.path.join(config['core']['data_dir'],
|
||||
self.ext_name))
|
||||
path.get_or_create_dir(data_dir_path)
|
||||
return data_dir_path
|
||||
|
||||
def get_command(self):
|
||||
"""Command to expose to command line users running ``mopidy``.
|
||||
|
||||
|
||||
26
tests/config/test_defaults.py
Normal file
26
tests/config/test_defaults.py
Normal file
@ -0,0 +1,26 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from mopidy import config
|
||||
|
||||
|
||||
def test_core_schema_has_cache_dir():
|
||||
assert 'cache_dir' in config._core_schema
|
||||
assert isinstance(config._core_schema['cache_dir'], config.Path)
|
||||
|
||||
|
||||
def test_core_schema_has_config_dir():
|
||||
assert 'config_dir' in config._core_schema
|
||||
assert isinstance(config._core_schema['config_dir'], config.Path)
|
||||
|
||||
|
||||
def test_core_schema_has_data_dir():
|
||||
assert 'data_dir' in config._core_schema
|
||||
assert isinstance(config._core_schema['data_dir'], config.Path)
|
||||
|
||||
|
||||
def test_core_schema_has_max_tracklist_length():
|
||||
assert 'max_tracklist_length' in config._core_schema
|
||||
max_tracklist_length_schema = config._core_schema['max_tracklist_length']
|
||||
assert isinstance(max_tracklist_length_schema, config.Integer)
|
||||
assert max_tracklist_length_schema._minimum == 1
|
||||
assert max_tracklist_length_schema._maximum == 10000
|
||||
@ -1,5 +1,7 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
import mock
|
||||
|
||||
import pkg_resources
|
||||
@ -11,7 +13,7 @@ from mopidy import config, exceptions, ext
|
||||
from tests import IsA, any_unicode
|
||||
|
||||
|
||||
class TestExtension(ext.Extension):
|
||||
class DummyExtension(ext.Extension):
|
||||
dist_name = 'Mopidy-Foobar'
|
||||
ext_name = 'foobar'
|
||||
version = '1.2.3'
|
||||
@ -20,10 +22,10 @@ class TestExtension(ext.Extension):
|
||||
return '[foobar]\nenabled = true'
|
||||
|
||||
|
||||
any_testextension = IsA(TestExtension)
|
||||
any_testextension = IsA(DummyExtension)
|
||||
|
||||
|
||||
class ExtensionTest(object):
|
||||
class TestExtension(object):
|
||||
|
||||
@pytest.fixture
|
||||
def extension(self):
|
||||
@ -53,8 +55,23 @@ class ExtensionTest(object):
|
||||
with pytest.raises(NotImplementedError):
|
||||
extension.setup(None)
|
||||
|
||||
def test_get_cache_dir_raises_assertion_error(self, extension):
|
||||
config = {'core': {'cache_dir': '/tmp'}}
|
||||
with pytest.raises(AssertionError): # ext_name not set
|
||||
extension.get_cache_dir(config)
|
||||
|
||||
class LoadExtensionsTest(object):
|
||||
def test_get_config_dir_raises_assertion_error(self, extension):
|
||||
config = {'core': {'config_dir': '/tmp'}}
|
||||
with pytest.raises(AssertionError): # ext_name not set
|
||||
extension.get_config_dir(config)
|
||||
|
||||
def test_get_data_dir_raises_assertion_error(self, extension):
|
||||
config = {'core': {'data_dir': '/tmp'}}
|
||||
with pytest.raises(AssertionError): # ext_name not set
|
||||
extension.get_data_dir(config)
|
||||
|
||||
|
||||
class TestLoadExtensions(object):
|
||||
|
||||
@pytest.yield_fixture
|
||||
def iter_entry_points_mock(self, request):
|
||||
@ -70,7 +87,7 @@ class LoadExtensionsTest(object):
|
||||
|
||||
def test_load_extensions(self, iter_entry_points_mock):
|
||||
mock_entry_point = mock.Mock()
|
||||
mock_entry_point.load.return_value = TestExtension
|
||||
mock_entry_point.load.return_value = DummyExtension
|
||||
|
||||
iter_entry_points_mock.return_value = [mock_entry_point]
|
||||
|
||||
@ -94,7 +111,7 @@ class LoadExtensionsTest(object):
|
||||
|
||||
def test_gets_instance(self, iter_entry_points_mock):
|
||||
mock_entry_point = mock.Mock()
|
||||
mock_entry_point.load.return_value = TestExtension()
|
||||
mock_entry_point.load.return_value = DummyExtension()
|
||||
|
||||
iter_entry_points_mock.return_value = [mock_entry_point]
|
||||
|
||||
@ -113,11 +130,11 @@ class LoadExtensionsTest(object):
|
||||
|
||||
def test_get_config_schema_fails(self, iter_entry_points_mock):
|
||||
mock_entry_point = mock.Mock()
|
||||
mock_entry_point.load.return_value = TestExtension
|
||||
mock_entry_point.load.return_value = DummyExtension
|
||||
|
||||
iter_entry_points_mock.return_value = [mock_entry_point]
|
||||
|
||||
with mock.patch.object(TestExtension, 'get_config_schema') as get:
|
||||
with mock.patch.object(DummyExtension, 'get_config_schema') as get:
|
||||
get.side_effect = Exception
|
||||
|
||||
assert ext.load_extensions() == []
|
||||
@ -125,11 +142,11 @@ class LoadExtensionsTest(object):
|
||||
|
||||
def test_get_default_config_fails(self, iter_entry_points_mock):
|
||||
mock_entry_point = mock.Mock()
|
||||
mock_entry_point.load.return_value = TestExtension
|
||||
mock_entry_point.load.return_value = DummyExtension
|
||||
|
||||
iter_entry_points_mock.return_value = [mock_entry_point]
|
||||
|
||||
with mock.patch.object(TestExtension, 'get_default_config') as get:
|
||||
with mock.patch.object(DummyExtension, 'get_default_config') as get:
|
||||
get.side_effect = Exception
|
||||
|
||||
assert ext.load_extensions() == []
|
||||
@ -137,22 +154,22 @@ class LoadExtensionsTest(object):
|
||||
|
||||
def test_get_command_fails(self, iter_entry_points_mock):
|
||||
mock_entry_point = mock.Mock()
|
||||
mock_entry_point.load.return_value = TestExtension
|
||||
mock_entry_point.load.return_value = DummyExtension
|
||||
|
||||
iter_entry_points_mock.return_value = [mock_entry_point]
|
||||
|
||||
with mock.patch.object(TestExtension, 'get_command') as get:
|
||||
with mock.patch.object(DummyExtension, 'get_command') as get:
|
||||
get.side_effect = Exception
|
||||
|
||||
assert ext.load_extensions() == []
|
||||
get.assert_called_once_with()
|
||||
|
||||
|
||||
class ValidateExtensionDataTest(object):
|
||||
class TestValidateExtensionData(object):
|
||||
|
||||
@pytest.fixture
|
||||
def ext_data(self):
|
||||
extension = TestExtension()
|
||||
extension = DummyExtension()
|
||||
|
||||
entry_point = mock.Mock()
|
||||
entry_point.name = extension.ext_name
|
||||
@ -221,3 +238,36 @@ class ValidateExtensionDataTest(object):
|
||||
def test_no_default_config(self, ext_data):
|
||||
ext_data = ext_data._replace(config_defaults=None)
|
||||
assert not ext.validate_extension_data(ext_data)
|
||||
|
||||
def test_get_cache_dir(self, ext_data):
|
||||
core_cache_dir = '/tmp'
|
||||
config = {'core': {'cache_dir': core_cache_dir}}
|
||||
extension = ext_data.extension
|
||||
|
||||
with mock.patch.object(ext.path, 'get_or_create_dir'):
|
||||
cache_dir = extension.get_cache_dir(config)
|
||||
|
||||
expected = os.path.join(core_cache_dir, extension.ext_name)
|
||||
assert cache_dir == expected
|
||||
|
||||
def test_get_config_dir(self, ext_data):
|
||||
core_config_dir = '/tmp'
|
||||
config = {'core': {'config_dir': core_config_dir}}
|
||||
extension = ext_data.extension
|
||||
|
||||
with mock.patch.object(ext.path, 'get_or_create_dir'):
|
||||
config_dir = extension.get_config_dir(config)
|
||||
|
||||
expected = os.path.join(core_config_dir, extension.ext_name)
|
||||
assert config_dir == expected
|
||||
|
||||
def test_get_data_dir(self, ext_data):
|
||||
core_data_dir = '/tmp'
|
||||
config = {'core': {'data_dir': core_data_dir}}
|
||||
extension = ext_data.extension
|
||||
|
||||
with mock.patch.object(ext.path, 'get_or_create_dir'):
|
||||
data_dir = extension.get_data_dir(config)
|
||||
|
||||
expected = os.path.join(core_data_dir, extension.ext_name)
|
||||
assert data_dir == expected
|
||||
|
||||
Loading…
Reference in New Issue
Block a user