[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