[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