[Pkg-mpd-commits] [python-mpd] 136/262: Imported Upstream version 0.4.2
Simon McVittie
smcv at debian.org
Sun May 22 18:16:38 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 6026c55f3ba6b3a6b4311b335258703c54688409
Author: kaliko <efrim at azylum.org>
Date: Mon Apr 9 21:12:08 2012 +0200
Imported Upstream version 0.4.2
---
CHANGES.txt | 12 +++--
README.md | 139 +++++++++++++++++++++++++++++++++++++++----------------
doc/commands.txt | 1 -
mpd.py | 41 ++++++++++------
setup.py | 2 +-
test.py | 89 ++++++++++++++++++++++++++---------
6 files changed, 204 insertions(+), 80 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d856b6f..2244ecb 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,11 @@
python-mpd2 Changes List
-=======================
+========================
+
+Changes in 0.4.2
+----------------
+
+* backward compatible unicode handling
+* added optional socket timeout parameter
Changes in 0.4.1
----------------
@@ -13,9 +19,9 @@ Changes in 0.4.0
* python3 support (python2.6 is minimum python version required)
* support for the upcoming client-to-client protocol
-* adding new commands of mpd (seekcur, prior, priorid)
+* added new commands of mpd (seekcur, prior, priorid)
* methods are explicit declared now, so they are shown in ipython
-* add unit tests
+* added unit tests
* documented API to add new commands (see Future Compatible)
diff --git a/README.md b/README.md
index 49aa853..b2ad025 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,26 @@
python-mpd2
-==========
+===========
-Difference to python-mpd
--------------------------
+Difference with python-mpd
+--------------------------
+
+python-mpd2 is a fork of the python-mpd.
+It is backward compatible to python-mpd, so it could act as drop-in replacement
+(tested with [sonata](http://sonata.berlios.de/)).
-python-mpd2 is a fork of the python-mpd. It is backward compatible to python-mpd, so it could act as drop-in replacement.
Current features list:
- python3 support (python2.6 is minimum python version required)
- support for the upcoming client-to-client protocol
- adding new commands of mpd v0.17 (seekcur, prio, prioid, config)
- remove of deprecated commands (volume)
- - methods are explicit declared now, so they are shown in ipython
+ - declare mpd commands explicit as method, so they are shown in ipython
- add unit tests
- documented API to add new commands (see Future Compatible)
+ - use unicode strings in all commands (optionally in python2, default in python3 - see Unicode Handling)
-I attempted to merge my changes into the original project, but never get a reponse.
-If you like this module, you could try contact the original author <jat at spatialrift.net> or join the discussion on the [issue tracker](http://jatreuman.indefero.net/p/python-mpd/issues/7/)
+If you like this module, you could try contact the original author <jat at spatialrift.net> or
+join the discussion on the [issue tracker](http://jatreuman.indefero.net/p/python-mpd/issues/7/)
Getting the latest source code
------------------------------
@@ -38,13 +42,21 @@ You can use the *--help* switch to *setup.py* for a complete list of commands
and their options. See the [Installing Python Modules](http://docs.python.org/inst/inst.html) document for more details.
-Using packages
---------------
-Until the python community adapt this package, here are some ready to use packages to test your applications:
+Getting the latest release
+--------------------------
+
+This python-mpd2 can be found on [pypi](http://pypi.python.org/pypi?:action=display&name=python-mpd2)
+
+###pypi:
+
+ $ pip install python-mpd2
+
-###debian:
+Until linux distributions adapt this package, here are some ready to use packages to test your applications:
-just add this line to your */etc/apt/sources.list*:
+### Debian
+
+Drop this line in */etc/apt/sources.list.d/python-mpd2.list*:
deb http://sima.azylum.org/debian unstable main
@@ -58,11 +70,20 @@ Key fingerprint :
Controls with *apt-key finger*.
-Then simply update/install *python-mpd2* with apt or aptitude:
+Then simply update/install *python-mpd2* or *python3-mpd* with apt or aptitude:
+
+### Arch Linux
+
+install [python-mpd2-git](https://aur.archlinux.org/packages.php?ID=57738) from AUR
+
+### Gentoo Linux
+
+An ebuid is available in the `laurentb` overlay.
-###archlinux
+ echo 'dev-python/python-mpd::laurentb **' >> /etc/portage/accept_keywords
+ layman -a laurentb
+ emerge -av python-mpd
-install [python-mpd-git](https://aur.archlinux.org/packages.php?ID=21531) from AUR
Packages for other distributions are welcome!
@@ -72,12 +93,15 @@ Using the client library
The client library can be used as follows:
- client = mpd.MPDClient() # create client object
- client.connect("localhost", 6600) # connect to localhost:6600
- print(client.mpd_version) # print the mpd version
- print(client.find("any", "house")) # print result of the command "find any house"
- client.close() # send the close command
- client.disconnect() # disconnect from the server
+```python
+client = mpd.MPDClient() # create client object
+client.connect("localhost", 6600, # connect to localhost:6600
+ timeout=10) # optional timeout in seconds (floats allowed), default: None
+print(client.mpd_version) # print the mpd version
+print(client.find("any", "house")) # print result of the command "find any house"
+client.close() # send the close command
+client.disconnect() # disconnect from the server
+```
A list of supported commands, their arguments (as MPD currently understands
them), and the functions used to parse their responses can be found in
@@ -86,28 +110,62 @@ them), and the functions used to parse their responses can be found in
Command lists are also supported using *command_list_ok_begin()* and
*command_list_end()*:
- client.command_list_ok_begin() # start a command list
- client.update() # insert the update command into the list
- client.status() # insert the status command into the list
- results = client.command_list_end() # results will be a list with the results
+```python
+client.command_list_ok_begin() # start a command list
+client.update() # insert the update command into the list
+client.status() # insert the status command into the list
+results = client.command_list_end() # results will be a list with the results
+```
Commands may also return iterators instead of lists if *iterate* is set to
*True*:
- client.iterate = True
- for song in client.playlistinfo():
- print song["file"]
+```python
+client.iterate = True
+for song in client.playlistinfo():
+ print song["file"]
+```
Each command have a *send_* and a *fetch_* variant, which allows to send a
mpd command and the fetch the result later. This is useful for the idle
command:
- client.send_idle()
- # do something else ...
- events = client.fetch_idle()
+```python
+client.send_idle()
+# do something else ...
+events = client.fetch_idle()
+```
Some more complex usage example can be found [here](http://jatreuman.indefero.net/p/python-mpd/doc/)
+
+Unicode Handling
+----------------
+To quote the mpd protocol documentation:
+
+> All data to be sent between the client and server must be encoded in UTF-8.
+
+In python3 unicode strings are default string type. So just pass these strings as arguments for mpd commands.
+
+For backward compatibility with python-mpd the python2 version accept both unicode strings (ex. u"♥") and unicoded encoded 8-bit strings (ex. "♥").
+It returns unicode encoded strings by default for the same reason.
+
+Using unicode strings should be prefered as it makes the transition to python3 easier.
+This way, decoding and encoding strings outside the library, is not needed to make function like len() behave correctly.
+To make MPDClient return unicode strings in python2 create the instance with the use_unicode parameter set to true.
+
+```python
+>>> import mpd
+>>> client = MPDClient(use_unicode=True)
+>>> client.urlhandlers()[0]
+u'http'
+>>> client.use_unicode = False # Can be switched back later
+>>> client.urlhandlers()[0]
+'http'
+```
+
+Use this option in python3 doesn't have an effect.
+
Future Compatible
-----------------
@@ -115,21 +173,22 @@ New commands or special handling of commands can be easily implemented.
Use *add_command()* or *remove_command()* to modify the commands of the
*MPDClient* class and all its instances.
-
- def fetch_cover(client):
- """"Take a MPDClient instance as its arguments and return mimetype and image"""
- # this command may come in the future.
- pass
- self.client.add_command("get_cover", fetch_cover)
- # remove the command, because it doesn't exist already.
- self.client.remove_command("get_cover")
+```python
+def fetch_cover(client):
+ """"Take a MPDClient instance as its arguments and return mimetype and image"""
+ # this command may come in the future.
+ pass
+self.client.add_command("get_cover", fetch_cover)
+# remove the command, because it doesn't exist already.
+self.client.remove_command("get_cover")
+```
Contacting the author
---------------------
Just connect me (Mic92) on github or via email (jthalheim at gmail.com).
-Usally I hang around on jabber: sonata at conference.codingteam.net
+Usually I hang around on jabber: sonata at conference.codingteam.net
You can contact the original author by emailing J. Alexander Treuman <jat at spatialrift.net>.
diff --git a/doc/commands.txt b/doc/commands.txt
index 6efc6a6..8da8101 100644
--- a/doc/commands.txt
+++ b/doc/commands.txt
@@ -17,7 +17,6 @@ setvol <int> -> fetch_nothing
single <bool> -> fetch_nothing
replay_gain_mode <str> -> fetch_nothing
replay_gain_status -> fetch_item
-volume <int> -> fetch_nothing
== Playback Control Commands
next -> fetch_nothing
diff --git a/mpd.py b/mpd.py
index f319993..617a3c5 100644
--- a/mpd.py
+++ b/mpd.py
@@ -15,6 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with python-mpd2. If not, see <http://www.gnu.org/licenses/>.
+import sys
import socket
from collections import Callable
@@ -23,6 +24,13 @@ ERROR_PREFIX = "ACK "
SUCCESS = "OK"
NEXT = "list_OK"
+IS_PYTHON2 = sys.version_info < (3, 0)
+if IS_PYTHON2:
+ decode_str = lambda s: s.decode("utf-8")
+ encode_str = lambda s: s if type(s) == str else (unicode(s)).encode("utf-8")
+else:
+ decode_str = lambda s: s
+ encode_str = lambda s: str(s)
class MPDError(Exception):
pass
@@ -156,8 +164,9 @@ _commands = {
}
class MPDClient():
- def __init__(self):
+ def __init__(self, use_unicode=False):
self.iterate = False
+ self.use_unicode = use_unicode
self._reset()
def _send(self, command, args, retval):
@@ -205,17 +214,19 @@ class MPDClient():
return retval
def _write_line(self, line):
- self._wfile.write(("%s\n" % line).encode('utf-8'))
+ self._wfile.write("%s\n" % line)
self._wfile.flush()
def _write_command(self, command, args=[]):
parts = [command]
for arg in args:
- parts.append('"%s"' % escape(str(arg)))
+ parts.append('"%s"' % escape(encode_str(arg)))
self._write_line(" ".join(parts))
def _read_line(self):
- line = self._rfile.readline().decode('utf-8')
+ line = self._rfile.readline()
+ if self.use_unicode:
+ line = decode_str(line)
if not line.endswith("\n"):
raise ConnectionError("Connection lost while reading line")
line = line.rstrip("\n")
@@ -350,7 +361,7 @@ class MPDClient():
return self._wrap_iterator(self._read_command_list())
def _hello(self):
- line = self._rfile.readline().decode('utf-8')
+ line = self._rfile.readline()
if not line.endswith("\n"):
raise ConnectionError("Connection lost while reading MPD hello")
line = line.rstrip("\n")
@@ -367,15 +378,16 @@ class MPDClient():
self._rfile = _NotConnected()
self._wfile = _NotConnected()
- def _connect_unix(self, path):
+ def _connect_unix(self, path, timeout):
if not hasattr(socket, "AF_UNIX"):
raise ConnectionError("Unix domain sockets not supported "
"on this platform")
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.settimeout(timeout)
sock.connect(path)
return sock
- def _connect_tcp(self, host, port):
+ def _connect_tcp(self, host, port, timeout):
try:
flags = socket.AI_ADDRCONFIG
except AttributeError:
@@ -389,26 +401,27 @@ class MPDClient():
try:
sock = socket.socket(af, socktype, proto)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
+ sock.settimeout(timeout)
sock.connect(sa)
return sock
except socket.error as e:
err = e
if sock is not None:
sock.close()
+ if err is not None:
+ raise err
else:
raise ConnectionError("getaddrinfo returns an empty list")
- raise err
-
- def connect(self, host, port):
+ def connect(self, host, port, timeout=None):
if self._sock is not None:
raise ConnectionError("Already connected")
if host.startswith("/"):
- self._sock = self._connect_unix(host)
+ self._sock = self._connect_unix(host, timeout)
else:
- self._sock = self._connect_tcp(host, port)
- self._rfile = self._sock.makefile("rb")
- self._wfile = self._sock.makefile("wb")
+ self._sock = self._connect_tcp(host, port, timeout)
+ self._rfile = self._sock.makefile("r")
+ self._wfile = self._sock.makefile("w")
try:
self._hello()
except:
diff --git a/setup.py b/setup.py
index 3e083e4..51c7c07 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,7 @@ along with python-mpd2. If not, see <http://www.gnu.org/licenses/>.\
setup(
name="python-mpd2",
- version="0.4.1",
+ version="0.4.2",
description="A Python MPD client library",
long_description=DESCRIPTION,
author="J. Thalheim",
diff --git a/test.py b/test.py
index 442457e..ad3bc3c 100755
--- a/test.py
+++ b/test.py
@@ -1,5 +1,7 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
import types
import sys
from socket import error as SocketError
@@ -18,27 +20,43 @@ except ImportError:
print("Please install unittest2 from pypi to run tests!")
sys.exit(1)
-# Alternate this to your setup
-# Make sure you have at least one song on your playlist
-MPD_HOST = "localhost"
-MPD_PORT = 6600
-MPD_PASSW = None
+def setup_environment():
+ # Alternate this to your setup
+ # Make sure you have at least one song on your playlist
+ global TEST_MPD_HOST, TEST_MPD_PORT, TEST_MPD_PASSWORD
+
+ if 'TEST_MPD_PORT' not in os.environ:
+ sys.stderr.write(
+ "You should set the TEST_MPD_PORT environment variable to point "
+ "to your test MPD running instance.\n")
+ sys.exit(255)
+
+ TEST_MPD_HOST = os.environ.get('TEST_MPD_HOST', "localhost")
+ TEST_MPD_PORT = int(os.environ['TEST_MPD_PORT'])
+ TEST_MPD_PASSWORD = os.environ.get('TEST_MPD_PASSWORD')
+
+setup_environment()
+
class TestMPDClient(unittest.TestCase):
+
+ longMessage = True
+
@classmethod
def setUpClass(self):
+ global TEST_MPD_HOST, TEST_MPD_PORT, TEST_MPD_PASSWORD
self.client = mpd.MPDClient()
self.idleclient = mpd.MPDClient()
try:
- self.client.connect(MPD_HOST, MPD_PORT)
- self.idleclient.connect(MPD_HOST, MPD_PORT)
+ self.client.connect(TEST_MPD_HOST, TEST_MPD_PORT)
+ self.idleclient.connect(TEST_MPD_HOST, TEST_MPD_PORT)
self.commands = self.client.commands()
- except (mpd.ConnectionError, SocketError) as e:
+ except SocketError as e:
raise Exception("Can't connect mpd! Start it or check the configuration: %s" % e)
- if MPD_PASSW != None:
+ if TEST_MPD_PASSWORD != None:
try:
- self.client.password(MPD_PASSW)
- self.idleclient.password(MPD_PASSW)
+ self.client.password(TEST_MPD_PASSWORD)
+ self.idleclient.password(TEST_MPD_PASSWORD)
except mpd.CommandError as e:
raise Exception("Fail to authenticate to mpd.")
@classmethod
@@ -129,12 +147,6 @@ class TestMPDClient(unittest.TestCase):
channels = self.client.channels()
self.assertNotIn("monty", channels)
- def test_connection_error(self):
- client2 = mpd.MPDClient()
- with self.assertRaises(mpd.ConnectionError) as cm:
- # should never return getaddrinfo
- client2.connect("255.255.255.255", 6600)
-
def test_commands_list(self):
"""
Test if all implemented commands are valid
@@ -149,11 +161,46 @@ class TestMPDClient(unittest.TestCase):
imple_cmds = (imple_cmds - sticker_cmds)
imple_cmds.add("sticker")
imple_cmds.remove("noidle")
- self.assertFalse(avaible_cmds - imple_cmds,
+
+ self.assertEqual(set(), avaible_cmds - imple_cmds,
"Not all commands supported by mpd are implemented!")
- long_desc = "Not all commands implemented by this library are supported by the current mpd.\n" + \
- "This either means the command list is wrong or mpd is not up-to-date."
- self.assertFalse(imple_cmds - avaible_cmds, long_desc)
+
+ long_desc = (
+ "Not all commands implemented by this library are supported by "
+ "the current mpd.\n" +
+ "This either means the command list is wrong or mpd is not "
+ "up-to-date.")
+
+ self.assertEqual(set(), imple_cmds - avaible_cmds, long_desc)
+
+ def test_unicode_as_command_args(self):
+ if sys.version_info < (3, 0):
+ raw_unicode = "☯☾☝♖✽".decode("utf-8")
+ res = self.client.find("file", raw_unicode)
+ self.assertIsInstance(res, list)
+
+ encoded_str = "☯☾☝♖✽"
+ res2 = self.client.find("file", encoded_str)
+ self.assertIsInstance(res2, list)
+ else:
+ res = self.client.find("file","☯☾☝♖✽")
+ self.assertIsInstance(res, list)
+
+ @unittest.skipIf(sys.version_info >= (3, 0),
+ "Test special unicode handling only if python2")
+ def test_unicode_as_reponse(self):
+ self.client.use_unicode = True
+ self.assertIsInstance(self.client.urlhandlers()[0], unicode)
+ self.client.use_unicode = False
+ self.assertIsInstance(self.client.urlhandlers()[0], str)
+
+ def test_numbers_as_command_args(self):
+ res = self.client.find("file", 1)
+
+ def test_timeout(self):
+ self.client.disconnect()
+ self.client.connect(TEST_MPD_HOST, TEST_MPD_PORT, timeout=5)
+ self.assertEqual(self.client._sock.gettimeout(), 5)
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