[Pkg-mpd-commits] [python-mpd] 54/91: base: Add direct commands for async overriding
Simon McVittie
smcv at debian.org
Sat Feb 24 14:55:35 UTC 2018
This is an automated email from the git hooks/post-receive script.
smcv pushed a commit to branch debian/master
in repository python-mpd.
commit 9a3eacce41389025d93a79f721f35d916aa05abb
Author: chrysn <chrysn at fsfe.org>
Date: Fri Apr 7 10:06:21 2017 +0200
base: Add direct commands for async overriding
This adds a distinct (but for synchronous and twisted use identical)
_parse_objects_direct method that can gets used everywhere the result is
returned right away.
Such methods also get an is_direct flag in their decorator, which allows
the asyncio implementation to work without an explicit list like
_wrap_iterator_parsers.
---
mpd/asyncio.py | 50 +++++++++++++++++++++-----------------------------
mpd/base.py | 46 +++++++++++++++++++++++++++-------------------
2 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/mpd/asyncio.py b/mpd/asyncio.py
index cd35379..8560f31 100644
--- a/mpd/asyncio.py
+++ b/mpd/asyncio.py
@@ -1,3 +1,21 @@
+"""Asynchronous access to MPD using the asyncio methods of Python 3.
+
+Interaction happens over the mpd.asyncio.MPDClient class, whose connect and
+command methods are coroutines.
+
+Some commands (eg. listall) additionally support the asynchronous iteration
+(aiter, `async for`) interface; using it allows the library user to obtain
+items of result as soon as they arrive.
+
+The .idle() method works as expected, but there .noidle() method is not
+implemented pending a notifying (and automatically idling on demand) interface.
+The asynchronous .idle() method is thus only suitable for clients which only
+want to send commands after an idle returned (eg. current song notification
+pushers).
+
+Command lists are currently not supported.
+"""
+
import asyncio
from functools import partial
@@ -5,7 +23,7 @@ from mpd.base import HELLO_PREFIX, ERROR_PREFIX, SUCCESS
from mpd.base import MPDClientBase
from mpd.base import MPDClient as SyncMPDClient
from mpd.base import ProtocolError, ConnectionError, CommandError
-from mpd.base import mpd_command_provider, mpd_commands
+from mpd.base import mpd_command_provider
class BaseCommandResult(asyncio.Future):
"""A future that carries its command/args/callback with it for the
@@ -163,8 +181,7 @@ class MPDClient(MPDClientBase):
return None
return line
- async def _parse_objects(self, lines, delimiters=[]):
- """Like _parse_objects, but waits for lines"""
+ async def _parse_objects_direct(self, lines, delimiters=[]):
obj = {}
while True:
line = await lines.get()
@@ -188,36 +205,11 @@ class MPDClient(MPDClientBase):
if obj:
yield obj
- # as the above works for everyone who calls `return _parse_objects` but
- # *not* for those that return list(_parse_objects(...))[0], that single
- # function is rewritten here to use the original _parse_objects
-
- @mpd_commands('count', 'currentsong', 'readcomments', 'stats', 'status')
- def _parse_object(self, lines):
- objs = list(SyncMPDClient._parse_objects(self, lines))
- if not objs:
- return {}
- return objs[0]
-
# command provider interface
- __wrap_async_iterator_parsers = [
- # the very ones that return _parse_object directly
- SyncMPDClient._parse_changes,
- SyncMPDClient._parse_database,
- SyncMPDClient._parse_messages,
- SyncMPDClient._parse_mounts,
- SyncMPDClient._parse_neighbors,
- SyncMPDClient._parse_outputs,
- SyncMPDClient._parse_playlists,
- SyncMPDClient._parse_plugins,
- SyncMPDClient._parse_songs,
- ]
-
@classmethod
def add_command(cls, name, callback):
- wrap_result = callback in cls.__wrap_async_iterator_parsers
- command_class = CommandResultIterable if wrap_result else CommandResult
+ command_class = CommandResultIterable if callback.mpd_commands_direct else CommandResult
if hasattr(cls, name):
# twisted silently ignores them; probably, i'll make an
# experience that'll make me take the same router at some point.
diff --git a/mpd/base.py b/mpd/base.py
index 3f47548..bed9598 100644
--- a/mpd/base.py
+++ b/mpd/base.py
@@ -117,11 +117,13 @@ class mpd_commands(object):
callback.
"""
- def __init__(self, *commands):
+ def __init__(self, *commands, is_direct=False):
self.commands = commands
+ self.is_direct = is_direct
def __call__(self, ob):
ob.mpd_commands = self.commands
+ ob.mpd_commands_direct = self.is_direct
return ob
@@ -232,6 +234,10 @@ class MPDClientBase(object):
if obj:
yield obj
+ # Use this instead of _parse_objects whenever the result is returned
+ # immediately in a command implementation
+ _parse_objects_direct = _parse_objects
+
def _parse_raw_stickers(self, lines):
for key, sticker in self._parse_pairs(lines):
value = sticker.split('=', 1)
@@ -242,13 +248,14 @@ class MPDClientBase(object):
NOOP = mpd_commands('close', 'kill')(Noop())
- @mpd_commands('plchangesposid')
+ @mpd_commands('plchangesposid', is_direct=True)
def _parse_changes(self, lines):
- return self._parse_objects(lines, ["cpos"])
+ return self._parse_objects_direct(lines, ["cpos"])
- @mpd_commands('listall', 'listallinfo', 'listfiles', 'lsinfo')
+ @mpd_commands('listall', 'listallinfo', 'listfiles', 'lsinfo',
+ is_direct=True)
def _parse_database(self, lines):
- return self._parse_objects(lines, ["file", "directory", "playlist"])
+ return self._parse_objects_direct(lines, ["file", "directory", "playlist"])
@mpd_commands('idle')
def _parse_idle(self, lines):
@@ -274,17 +281,17 @@ class MPDClientBase(object):
seen = key
yield value
- @mpd_commands('readmessages')
+ @mpd_commands('readmessages', is_direct=True)
def _parse_messages(self, lines):
- return self._parse_objects(lines, ["channel"])
+ return self._parse_objects_direct(lines, ["channel"])
- @mpd_commands('listmounts')
+ @mpd_commands('listmounts', is_direct=True)
def _parse_mounts(self, lines):
- return self._parse_objects(lines, ["mount"])
+ return self._parse_objects_direct(lines, ["mount"])
- @mpd_commands('listneighbors')
+ @mpd_commands('listneighbors', is_direct=True)
def _parse_neighbors(self, lines):
- return self._parse_objects(lines, ["neighbor"])
+ return self._parse_objects_direct(lines, ["neighbor"])
@mpd_commands(
'add', 'addtagid', 'clear', 'clearerror', 'cleartagid', 'consume',
@@ -309,28 +316,29 @@ class MPDClientBase(object):
return {}
return objs[0]
- @mpd_commands('outputs')
+ @mpd_commands('outputs', is_direct=True)
def _parse_outputs(self, lines):
- return self._parse_objects(lines, ["outputid"])
+ return self._parse_objects_direct(lines, ["outputid"])
@mpd_commands('playlist')
def _parse_playlist(self, lines):
for key, value in self._parse_pairs(lines, ":"):
yield value
- @mpd_commands('listplaylists')
+ @mpd_commands('listplaylists', is_direct=True)
def _parse_playlists(self, lines):
- return self._parse_objects(lines, ["playlist"])
+ return self._parse_objects_direct(lines, ["playlist"])
- @mpd_commands('decoders')
+ @mpd_commands('decoders', is_direct=True)
def _parse_plugins(self, lines):
- return self._parse_objects(lines, ["plugin"])
+ return self._parse_objects_direct(lines, ["plugin"])
@mpd_commands(
'find', 'listplaylistinfo', 'playlistfind', 'playlistid',
- 'playlistinfo', 'playlistsearch', 'plchanges', 'search', 'sticker find')
+ 'playlistinfo', 'playlistsearch', 'plchanges', 'search',
+ 'sticker find', is_direct=True)
def _parse_songs(self, lines):
- return self._parse_objects(lines, ["file"])
+ return self._parse_objects_direct(lines, ["file"])
@mpd_commands('sticker get')
def _parse_sticker(self, lines):
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mpd/python-mpd.git
More information about the Pkg-mpd-commits
mailing list