mpd: Update docs

This commit is contained in:
Thomas Adamcik 2014-01-30 23:51:31 +01:00
parent 2e6f716b72
commit a7f4ffb124
3 changed files with 76 additions and 6 deletions

View File

@ -7,6 +7,13 @@ For details on how to use Mopidy's MPD server, see :ref:`ext-mpd`.
.. automodule:: mopidy.mpd
:synopsis: MPD server frontend
MPD tokenizer
=============
.. automodule:: mopidy.mpd.tokenize
:synopsis: MPD request tokenizer
:members:
MPD dispatcher
==============

View File

@ -37,6 +37,7 @@ def load_protocol_modules():
def INT(value):
"""Converts a value that matches [+-]?\d+ into and integer."""
if value is None:
raise ValueError('None is not a valid integer')
# TODO: check for whitespace via value != value.strip()?
@ -44,6 +45,7 @@ def INT(value):
def UINT(value):
"""Converts a value that matches \d+ into and integer."""
if value is None:
raise ValueError('None is not a valid integer')
if not value.isdigit():
@ -52,13 +54,19 @@ def UINT(value):
def BOOL(value):
"""Convert the values 0 and 1 into booleans."""
if value in ('1', '0'):
return bool(int(value))
raise ValueError('%r is not 0 or 1' % value)
def RANGE(value):
# TODO: test and check that values are positive
"""Convert a single integer or range spec into a slice
`n` should become `slice(n, n+1)`
`n:` should become `slice(n, None)`
`n:m` should become `slice(n, m)` and `m > n` must hold
"""
if ':' in value:
start, stop = value.split(':', 1)
start = UINT(start)
@ -75,10 +83,38 @@ def RANGE(value):
class Commands(object):
"""Collection of MPD commands to expose to users.
Normally used through the global instance which command handlers have been
installed into.
"""
def __init__(self):
self.handlers = {}
# TODO: consider removing auth_required and list_command in favour of
# additional command instances to register in?
def add(self, name, auth_required=True, list_command=True, **validators):
"""Create a decorator that registers a handler + validation rules.
Additional keyword arguments are treated as converts/validators to
apply to tokens converting them to proper python types.
Requirements for valid handlers:
- must accept a context argument as the first arg.
- may not use variable keyword arguments, ``**kwargs``.
- may use variable arguments ``*args`` *or* a mix of required and
optional arguments.
Decorator returns the unwrapped function so that tests etc can use the
functions with values with correct python types instead of strings.
:param string name: Name of the command being registered.
:param bool auth_required: If authorization is required.
:param bool list_command: If command should be listed in reflection.
"""
def wrapper(func):
if name in self.handlers:
raise ValueError('%s already registered' % name)
@ -118,12 +154,21 @@ class Commands(object):
return func
return wrapper
def call(self, args, context=None):
if not args:
def call(self, tokens, context=None):
"""Find and run the handler registered for the given command.
If the handler was registered with any converters/validators there will
be run before calling the real handler.
:param list tokens: List of tokens to process
:param context: MPD context.
:type context: :class:`~mopidy.mpd.dispatcher.MpdContext`
"""
if not tokens:
raise exceptions.MpdNoCommand()
if args[0] not in self.handlers:
raise exceptions.MpdUnknownCommand(command=args[0])
return self.handlers[args[0]](context, *args[1:])
if tokens[0] not in self.handlers:
raise exceptions.MpdUnknownCommand(command=tokens[0])
return self.handlers[tokens[0]](context, *tokens[1:])
#: Global instance to install commands into

View File

@ -39,6 +39,23 @@ UNESCAPE_RE = re.compile(r'\\(.)') # Backslash escapes any following char.
def split(line):
"""Splits a line into tokens using same rules as MPD.
- Lines may not start with whitespace
- Tokens are split by arbitrary amount of spaces or tabs
- First token must match `[a-z][a-z0-9_]*`
- Remaining tokens can be unquoted or quoted tokens.
- Unquoted tokens consist of all printable characters except double quotes,
single quotes, spaces and tabs.
- Quoted tokens are surrounded by a matching pair of double quotes.
- The closing quote must be followed by space, tab or end of line.
- Any value is allowed inside a quoted token. Including double quotes,
assuming it is correctly escaped.
- Backslash inside a quoted token is used to escape the following
character.
For examples see the tests for this function.
"""
if not line.strip():
raise exceptions.MpdNoCommand('No command given')
match = WORD_RE.match(line)
@ -60,6 +77,7 @@ def split(line):
def _determine_error_message(remainder):
"""Helper to emulate MPD errors."""
# Following checks are simply to match MPD error messages:
match = BAD_QUOTED_PARAM_RE.match(remainder)
if match: