[Pkg-mpd-commits] [python-mpd] 86/262: Use monkey patching to make mpd commands explicit
Simon McVittie
smcv at debian.org
Sun May 22 18:16:28 UTC 2016
This is an automated email from the git hooks/post-receive script.
smcv pushed a commit to branch upstream
in repository python-mpd.
commit 4d15d68f0d87f8461b181251f4eb32c3af9101e1
Author: Jörg Thalheim <jthalheim at gmail.com>
Date: Tue Feb 7 21:10:34 2012 +0100
Use monkey patching to make mpd commands explicit
This allow it also to inject mpd methods at runtime
---
mpd.py | 254 ++++++++++++++++++++++++++++++++++------------------------------
test.py | 14 +++-
2 files changed, 148 insertions(+), 120 deletions(-)
diff --git a/mpd.py b/mpd.py
index 8dff2ef..21eef49 100644
--- a/mpd.py
+++ b/mpd.py
@@ -52,155 +52,136 @@ class _NotConnected(object):
def _dummy(*args):
raise ConnectionError("Not connected")
-class MPDClient(object):
+_commands = {
+ # Status Commands
+ "clearerror": "_fetch_nothing",
+ "currentsong": "_fetch_object",
+ "idle": "_fetch_list",
+ "noidle": None,
+ "status": "_fetch_object",
+ "stats": "_fetch_object",
+ # Playback Option Commands
+ "consume": "_fetch_nothing",
+ "crossfade": "_fetch_nothing",
+ "mixrampdb": "_fetch_nothing",
+ "mixrampdelay": "_fetch_nothing",
+ "random": "_fetch_nothing",
+ "repeat": "_fetch_nothing",
+ "setvol": "_fetch_nothing",
+ "single": "_fetch_nothing",
+ "replay_gain_mode": "_fetch_nothing",
+ "replay_gain_status": "_fetch_item",
+ "volume": "_fetch_nothing",
+ # Playback Control Commands
+ "next": "_fetch_nothing",
+ "pause": "_fetch_nothing",
+ "play": "_fetch_nothing",
+ "playid": "_fetch_nothing",
+ "previous": "_fetch_nothing",
+ "seek": "_fetch_nothing",
+ "seekid": "_fetch_nothing",
+ "stop": "_fetch_nothing",
+ # Playlist Commands
+ "add": "_fetch_nothing",
+ "addid": "_fetch_item",
+ "clear": "_fetch_nothing",
+ "delete": "_fetch_nothing",
+ "deleteid": "_fetch_nothing",
+ "move": "_fetch_nothing",
+ "moveid": "_fetch_nothing",
+ "playlist": "_fetch_playlist",
+ "playlistfind": "_fetch_songs",
+ "playlistid": "_fetch_songs",
+ "playlistinfo": "_fetch_songs",
+ "playlistsearch": "_fetch_songs",
+ "plchanges": "_fetch_songs",
+ "plchangesposid": "_fetch_changes",
+ "shuffle": "_fetch_nothing",
+ "swap": "_fetch_nothing",
+ "swapid": "_fetch_nothing",
+ # Stored Playlist Commands
+ "listplaylist": "_fetch_list",
+ "listplaylistinfo": "_fetch_songs",
+ "listplaylists": "_fetch_playlists",
+ "load": "_fetch_nothing",
+ "playlistadd": "_fetch_nothing",
+ "playlistclear": "_fetch_nothing",
+ "playlistdelete": "_fetch_nothing",
+ "playlistmove": "_fetch_nothing",
+ "rename": "_fetch_nothing",
+ "rm": "_fetch_nothing",
+ "save": "_fetch_nothing",
+ # Database Commands
+ "count": "_fetch_object",
+ "find": "_fetch_songs",
+ "findadd": "_fetch_nothing",
+ "list": "_fetch_list",
+ "listall": "_fetch_database",
+ "listallinfo": "_fetch_database",
+ "lsinfo": "_fetch_database",
+ "search": "_fetch_songs",
+ "update": "_fetch_item",
+ "rescan": "_fetch_item",
+ # Sticker Commands
+ "sticker get": "_fetch_item",
+ "sticker set": "_fetch_nothing",
+ "sticker delete": "_fetch_nothing",
+ "sticker list": "_fetch_list",
+ "sticker find": "_fetch_songs",
+ # Connection Commands
+ "close": None,
+ "kill": None,
+ "password": "_fetch_nothing",
+ "ping": "_fetch_nothing",
+ # Audio Output Commands
+ "disableoutput": "_fetch_nothing",
+ "enableoutput": "_fetch_nothing",
+ "outputs": "_fetch_outputs",
+ # Reflection Commands
+ "commands": "_fetch_list",
+ "notcommands": "_fetch_list",
+ "tagtypes": "_fetch_list",
+ "urlhandlers": "_fetch_list",
+ "decoders": "_fetch_plugins",
+}
+
+class MPDClient():
def __init__(self):
self.iterate = False
self._reset()
- self._commands = {
- # Status Commands
- "clearerror": self._fetch_nothing,
- "currentsong": self._fetch_object,
- "idle": self._fetch_list,
- "noidle": None,
- "status": self._fetch_object,
- "stats": self._fetch_object,
- # Playback Option Commands
- "consume": self._fetch_nothing,
- "crossfade": self._fetch_nothing,
- "mixrampdb": self._fetch_nothing,
- "mixrampdelay": self._fetch_nothing,
- "random": self._fetch_nothing,
- "repeat": self._fetch_nothing,
- "setvol": self._fetch_nothing,
- "single": self._fetch_nothing,
- "replay_gain_mode": self._fetch_nothing,
- "replay_gain_status": self._fetch_item,
- "volume": self._fetch_nothing,
- # Playback Control Commands
- "next": self._fetch_nothing,
- "pause": self._fetch_nothing,
- "play": self._fetch_nothing,
- "playid": self._fetch_nothing,
- "previous": self._fetch_nothing,
- "seek": self._fetch_nothing,
- "seekid": self._fetch_nothing,
- "stop": self._fetch_nothing,
- # Playlist Commands
- "add": self._fetch_nothing,
- "addid": self._fetch_item,
- "clear": self._fetch_nothing,
- "delete": self._fetch_nothing,
- "deleteid": self._fetch_nothing,
- "move": self._fetch_nothing,
- "moveid": self._fetch_nothing,
- "playlist": self._fetch_playlist,
- "playlistfind": self._fetch_songs,
- "playlistid": self._fetch_songs,
- "playlistinfo": self._fetch_songs,
- "playlistsearch": self._fetch_songs,
- "plchanges": self._fetch_songs,
- "plchangesposid": self._fetch_changes,
- "shuffle": self._fetch_nothing,
- "swap": self._fetch_nothing,
- "swapid": self._fetch_nothing,
- # Stored Playlist Commands
- "listplaylist": self._fetch_list,
- "listplaylistinfo": self._fetch_songs,
- "listplaylists": self._fetch_playlists,
- "load": self._fetch_nothing,
- "playlistadd": self._fetch_nothing,
- "playlistclear": self._fetch_nothing,
- "playlistdelete": self._fetch_nothing,
- "playlistmove": self._fetch_nothing,
- "rename": self._fetch_nothing,
- "rm": self._fetch_nothing,
- "save": self._fetch_nothing,
- # Database Commands
- "count": self._fetch_object,
- "find": self._fetch_songs,
- "findadd": self._fetch_nothing,
- "list": self._fetch_list,
- "listall": self._fetch_database,
- "listallinfo": self._fetch_database,
- "lsinfo": self._fetch_database,
- "search": self._fetch_songs,
- "update": self._fetch_item,
- "rescan": self._fetch_item,
- # Sticker Commands
- "sticker get": self._fetch_item,
- "sticker set": self._fetch_nothing,
- "sticker delete": self._fetch_nothing,
- "sticker list": self._fetch_list,
- "sticker find": self._fetch_songs,
- # Connection Commands
- "close": None,
- "kill": None,
- "password": self._fetch_nothing,
- "ping": self._fetch_nothing,
- # Audio Output Commands
- "disableoutput": self._fetch_nothing,
- "enableoutput": self._fetch_nothing,
- "outputs": self._fetch_outputs,
- # Reflection Commands
- "commands": self._fetch_list,
- "notcommands": self._fetch_list,
- "tagtypes": self._fetch_list,
- "urlhandlers": self._fetch_list,
- "decoders": self._fetch_plugins,
- }
- def __getattr__(self, attr):
- if attr.startswith("send_"):
- command = attr.replace("send_", "", 1)
- wrapper = self._send
- elif attr.startswith("fetch_"):
- command = attr.replace("fetch_", "", 1)
- wrapper = self._fetch
- else:
- command = attr
- wrapper = self._execute
- if command not in self._commands:
- command = command.replace("_", " ")
- if command not in self._commands:
- raise AttributeError("'%s' object has no attribute '%s'" %
- (self.__class__.__name__, attr))
- return lambda *args: wrapper(command, args)
-
- def _send(self, command, args):
+ def _send(self, command, args, retval):
if self._command_list is not None:
raise CommandListError("Cannot use send_%s in a command list" %
- command.replace(" ", "_"))
+ command)
self._write_command(command, args)
- retval = self._commands[command]
if retval is not None:
self._pending.append(command)
- def _fetch(self, command, args=None):
+ def _fetch(self, command, args, retval):
if self._command_list is not None:
raise CommandListError("Cannot use fetch_%s in a command list" %
- command.replace(" ", "_"))
+ command)
if self._iterating:
raise IteratingError("Cannot use fetch_%s while iterating" %
- command.replace(" ", "_"))
+ command)
if not self._pending:
raise PendingCommandError("No pending commands to fetch")
if self._pending[0] != command:
raise PendingCommandError("'%s' is not the currently "
"pending command" % command)
del self._pending[0]
- retval = self._commands[command]
if isinstance(retval, Callable):
return retval()
return retval
- def _execute(self, command, args):
+ def _execute(self, command, args, retval):
if self._iterating:
raise IteratingError("Cannot execute '%s' while iterating" %
command)
if self._pending:
raise PendingCommandError("Cannot execute '%s' with "
"pending commands" % command)
- retval = self._commands[command]
if self._command_list is not None:
if not isinstance(retval, Callable):
raise CommandListError("'%s' not allowed in command list" %
@@ -449,6 +430,41 @@ class MPDClient(object):
self._write_command("command_list_end")
return self._fetch_command_list()
+ @classmethod
+ def add_command(cls, name, callback):
+ method = newFunction(cls._execute, key, callback)
+ send_method = newFunction(cls._send, key, callback)
+ fetch_method = newFunction(cls._fetch, key, callback)
+
+ # create new mpd commands as function in the tree flavors:
+ # normal, with "send_"-prefix and with "fetch_"-prefix
+ escaped_name = name.replace(" ", "_")
+ setattr(cls, escaped_name, method)
+ setattr(cls, "send_"+escaped_name, send_method)
+ setattr(cls, "fetch_"+escaped_name, fetch_method)
+
+ @classmethod
+ def remove_command(cls, name):
+ if not hasattr(cls, name): return
+ name = name.replace(" ", "_")
+ delattr(cls, str(name))
+ delattr(cls, str("send_" + name))
+ delattr(cls, str("fetch_" + name))
+
+def bound_decorator(self, function):
+ """ bind decorator to self """
+ def decorator(*args, **kwargs):
+ return function(self, *args, **kwargs)
+ return decorator
+
+def newFunction(wrapper, name, returnValue):
+ def decorator(self, *args):
+ return wrapper(self, name, args, bound_decorator(self, returnValue))
+ return decorator
+
+for key, value in _commands.items():
+ returnValue = None if value is None else MPDClient.__dict__[value]
+ MPDClient.add_command(key, returnValue)
def escape(text):
return text.replace("\\", "\\\\").replace('"', '\\"')
diff --git a/test.py b/test.py
index 489206d..ec988b2 100755
--- a/test.py
+++ b/test.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
import unittest
-from mpd import MPDClient
+from mpd import MPDClient, CommandError
# Alternate this to your setup
# Make sure you have at least one song on your playlist
@@ -60,6 +60,18 @@ class TestMPDClient(unittest.TestCase):
self.client.update()
event = self.idleclient.fetch_idle()
self.assertEqual(event, ['update'])
+ def test_add_and_remove_command(self):
+ self.client.add_command("awesome command", MPDClient._fetch_nothing)
+ self.assertTrue(hasattr(self.client, "awesome_command"))
+ self.assertTrue(hasattr(self.client, "send_awesome_command"))
+ self.assertTrue(hasattr(self.client, "fetch_awesome_command"))
+ # should be unknown by mpd
+ with self.assertRaises(CommandError):
+ self.client.awesome_command()
+ self.client.remove_command("awesome_command")
+ self.assertFalse(hasattr(self.client, "awesome_command"))
+ self.assertFalse(hasattr(self.client, "send_awesome_command"))
+ self.assertFalse(hasattr(self.client, "fetch_awesome_command"))
if __name__ == '__main__':
unittest.main()
--
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