docs: Document config API

This commit is contained in:
Stein Magnus Jodal 2013-04-14 13:58:37 +02:00
parent 6df42299b4
commit 2d0e5ac117
7 changed files with 120 additions and 31 deletions

37
docs/api/config.rst Normal file
View 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:

View File

@ -14,4 +14,5 @@ API reference
audio
frontends
ext
config
http

View File

@ -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',
]

View File

@ -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())

View File

@ -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 = {}

View File

@ -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()

View File

@ -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))