docs: Document config API
This commit is contained in:
parent
6df42299b4
commit
2d0e5ac117
37
docs/api/config.rst
Normal file
37
docs/api/config.rst
Normal file
@ -0,0 +1,37 @@
|
||||
.. _config-api:
|
||||
|
||||
**********
|
||||
Config API
|
||||
**********
|
||||
|
||||
.. automodule:: mopidy.config
|
||||
:synopsis: Config API for config loading and validation
|
||||
:members:
|
||||
|
||||
|
||||
Config section schemas
|
||||
======================
|
||||
|
||||
.. inheritance-diagram:: mopidy.config.schemas
|
||||
|
||||
.. automodule:: mopidy.config.schemas
|
||||
:synopsis: Config section validation schemas
|
||||
:members:
|
||||
|
||||
|
||||
Config value types
|
||||
==================
|
||||
|
||||
.. inheritance-diagram:: mopidy.config.types
|
||||
|
||||
.. automodule:: mopidy.config.types
|
||||
:synopsis: Config value validation types
|
||||
:members:
|
||||
|
||||
|
||||
Config value validators
|
||||
=======================
|
||||
|
||||
.. automodule:: mopidy.config.validators
|
||||
:synopsis: Config value validators
|
||||
:members:
|
||||
@ -14,4 +14,5 @@ API reference
|
||||
audio
|
||||
frontends
|
||||
ext
|
||||
config
|
||||
http
|
||||
|
||||
@ -81,6 +81,7 @@ on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.extlinks',
|
||||
'sphinx.ext.inheritance_diagram',
|
||||
'sphinx.ext.graphviz',
|
||||
'sphinx.ext.viewcode',
|
||||
]
|
||||
|
||||
@ -37,7 +37,7 @@ core_schemas = [_logging_schema, _loglevels_schema, _audio_schema, _proxy_schema
|
||||
|
||||
|
||||
def read(config_file):
|
||||
"""Helper to load defaults in same way across core and extensions."""
|
||||
"""Helper to load config defaults in same way across core and extensions"""
|
||||
with io.open(config_file, 'rb') as filehandle:
|
||||
return filehandle.read()
|
||||
|
||||
@ -118,7 +118,7 @@ def _validate(raw_config, schemas):
|
||||
|
||||
|
||||
def parse_override(override):
|
||||
"""Parse section/key=value override."""
|
||||
"""Parse ``section/key=value`` command line overrides"""
|
||||
section, remainder = override.split('/', 1)
|
||||
key, value = remainder.split('=', 1)
|
||||
return (section.strip(), key.strip(), value.strip())
|
||||
|
||||
@ -59,6 +59,8 @@ class ConfigSchema(object):
|
||||
return self._schema[key]
|
||||
|
||||
def format(self, values):
|
||||
"""Returns the schema as a config section with the given ``values``
|
||||
filled in"""
|
||||
# TODO: should the output be encoded utf-8 since we use that in
|
||||
# serialize for strings?
|
||||
lines = ['[%s]' % self.name]
|
||||
@ -70,6 +72,8 @@ class ConfigSchema(object):
|
||||
return '\n'.join(lines)
|
||||
|
||||
def convert(self, items):
|
||||
"""Validates the given ``items`` using the config schema and returns
|
||||
clean values"""
|
||||
errors = {}
|
||||
values = {}
|
||||
|
||||
|
||||
@ -25,23 +25,32 @@ class ConfigValue(object):
|
||||
the code interacting with the config should simply skip None config values.
|
||||
"""
|
||||
|
||||
#: Collection of valid choices for converted value. Must be combined with
|
||||
#: :function:`validate_choices` in :method:`validate` do any thing.
|
||||
choices = None
|
||||
"""
|
||||
Collection of valid choices for converted value. Must be combined with
|
||||
:func:`~mopidy.config.validators.validate_choice` in :meth:`deserialize`
|
||||
do any thing.
|
||||
"""
|
||||
|
||||
#: Minimum of converted value. Must be combined with
|
||||
#: :function:`validate_minimum` in :method:`validate` do any thing.
|
||||
minimum = None
|
||||
"""
|
||||
Minimum of converted value. Must be combined with
|
||||
:func:`~mopidy.config.validators.validate_minimum` in :meth:`deserialize`
|
||||
do any thing.
|
||||
"""
|
||||
|
||||
#: Maximum of converted value. Must be combined with
|
||||
#: :function:`validate_maximum` in :method:`validate` do any thing.
|
||||
maximum = None
|
||||
"""
|
||||
Maximum of converted value. Must be combined with
|
||||
:func:`~mopidy.config.validators.validate_maximum` in :meth:`deserialize`
|
||||
do any thing.
|
||||
"""
|
||||
|
||||
#: Indicate if this field is required.
|
||||
optional = None
|
||||
"""Indicate if this field is required."""
|
||||
|
||||
#: Indicate if we should mask the when printing for human consumption.
|
||||
secret = None
|
||||
"""Indicate if we should mask the when printing for human consumption."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.choices = kwargs.get('choices')
|
||||
@ -66,9 +75,9 @@ class ConfigValue(object):
|
||||
|
||||
|
||||
class String(ConfigValue):
|
||||
"""String values.
|
||||
"""String value
|
||||
|
||||
Supports: optional, choices and secret.
|
||||
Supported kwargs: ``optional``, ``choices``, and ``secret``.
|
||||
"""
|
||||
def deserialize(self, value):
|
||||
value = value.strip()
|
||||
@ -83,9 +92,9 @@ class String(ConfigValue):
|
||||
|
||||
|
||||
class Integer(ConfigValue):
|
||||
"""Integer values.
|
||||
"""Integer value
|
||||
|
||||
Supports: choices, minimum, maximum and secret.
|
||||
Supported kwargs: ``choices``, ``minimum``, ``maximum``, and ``secret``
|
||||
"""
|
||||
def deserialize(self, value):
|
||||
value = int(value)
|
||||
@ -96,9 +105,15 @@ class Integer(ConfigValue):
|
||||
|
||||
|
||||
class Boolean(ConfigValue):
|
||||
"""Boolean values.
|
||||
"""Boolean value
|
||||
|
||||
Supports: secret.
|
||||
Accepts ``1``, ``yes``, ``true``, and ``on`` with any casing as
|
||||
:class:`True`.
|
||||
|
||||
Accepts ``0``, ``no``, ``false``, and ``off`` with any casing as
|
||||
:class:`False`.
|
||||
|
||||
Supported kwargs: ``secret``
|
||||
"""
|
||||
true_values = ('1', 'yes', 'true', 'on')
|
||||
false_values = ('0', 'no', 'false', 'off')
|
||||
@ -119,9 +134,11 @@ class Boolean(ConfigValue):
|
||||
|
||||
|
||||
class List(ConfigValue):
|
||||
"""List values split by comma or newline.
|
||||
"""List value
|
||||
|
||||
Supports: optional and secret.
|
||||
Supports elements split by commas or newlines.
|
||||
|
||||
Supported kwargs: ``optional`` and ``secret``
|
||||
"""
|
||||
def deserialize(self, value):
|
||||
validators.validate_required(value, not self.optional)
|
||||
@ -136,9 +153,12 @@ class List(ConfigValue):
|
||||
|
||||
|
||||
class LogLevel(ConfigValue):
|
||||
"""Log level values.
|
||||
"""Log level value
|
||||
|
||||
Supports: secret.
|
||||
Expects one of ``critical``, ``error``, ``warning``, ``info``, ``debug``
|
||||
with any casing.
|
||||
|
||||
Supported kwargs: ``secret``
|
||||
"""
|
||||
levels = {
|
||||
'critical': logging.CRITICAL,
|
||||
@ -157,9 +177,9 @@ class LogLevel(ConfigValue):
|
||||
|
||||
|
||||
class Hostname(ConfigValue):
|
||||
"""Hostname values.
|
||||
"""Hostname value
|
||||
|
||||
Supports: optional and secret.
|
||||
Supported kwargs: ``optional`` and ``secret``
|
||||
"""
|
||||
def deserialize(self, value):
|
||||
validators.validate_required(value, not self.optional)
|
||||
@ -173,9 +193,11 @@ class Hostname(ConfigValue):
|
||||
|
||||
|
||||
class Port(Integer):
|
||||
"""Port values limited to 1-65535.
|
||||
"""Port value
|
||||
|
||||
Supports: choices and secret.
|
||||
Expects integer in the range 1-65535
|
||||
|
||||
Supported kwargs: ``choices`` and ``secret``
|
||||
"""
|
||||
# TODO: consider probing if port is free or not?
|
||||
def __init__(self, **kwargs):
|
||||
@ -194,9 +216,21 @@ class ExpandedPath(bytes):
|
||||
|
||||
|
||||
class Path(ConfigValue):
|
||||
"""File system path that will be expanded.
|
||||
"""File system path
|
||||
|
||||
Supports: optional, choices and secret.
|
||||
The following expansions of the path will be done:
|
||||
|
||||
- ``~`` to the current user's home directory
|
||||
|
||||
- ``$XDG_CACHE_DIR`` according to the XDG spec
|
||||
|
||||
- ``$XDG_CONFIG_DIR`` according to the XDG spec
|
||||
|
||||
- ``$XDG_DATA_DIR`` according to the XDG spec
|
||||
|
||||
- ``$XDG_MUSIC_DIR`` according to the XDG spec
|
||||
|
||||
Supported kwargs: ``optional``, ``choices``, and ``secret``
|
||||
"""
|
||||
def deserialize(self, value):
|
||||
value = value.strip()
|
||||
|
||||
@ -4,26 +4,38 @@ from __future__ import unicode_literals
|
||||
|
||||
|
||||
def validate_required(value, required):
|
||||
"""Required validation, normally called in config value's validate() on the
|
||||
raw string, _not_ the converted value."""
|
||||
"""Validate that ``value`` is set if ``required``
|
||||
|
||||
Normally called in :meth:`~mopidy.config.types.ConfigValue.deserialize` on
|
||||
the raw string, _not_ the converted value.
|
||||
"""
|
||||
if required and not value.strip():
|
||||
raise ValueError('must be set.')
|
||||
|
||||
|
||||
def validate_choice(value, choices):
|
||||
"""Choice validation, normally called in config value's validate()."""
|
||||
"""Validate that ``value`` is one of the ``choices``
|
||||
|
||||
Normally called in :meth:`~mopidy.config.types.ConfigValue.deserialize`.
|
||||
"""
|
||||
if choices is not None and value not in choices:
|
||||
names = ', '.join(repr(c) for c in choices)
|
||||
raise ValueError('must be one of %s, not %s.' % (names, value))
|
||||
|
||||
|
||||
def validate_minimum(value, minimum):
|
||||
"""Minimum validation, normally called in config value's validate()."""
|
||||
"""Validate that ``value`` is at least ``minimum``
|
||||
|
||||
Normally called in :meth:`~mopidy.config.types.ConfigValue.deserialize`.
|
||||
"""
|
||||
if minimum is not None and value < minimum:
|
||||
raise ValueError('%r must be larger than %r.' % (value, minimum))
|
||||
|
||||
|
||||
def validate_maximum(value, maximum):
|
||||
"""Maximum validation, normally called in config value's validate()."""
|
||||
"""Validate that ``value`` is at most ``maximum``
|
||||
|
||||
Normally called in :meth:`~mopidy.config.types.ConfigValue.deserialize`.
|
||||
"""
|
||||
if maximum is not None and value > maximum:
|
||||
raise ValueError('%r must be smaller than %r.' % (value, maximum))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user