[Pkg-mpd-commits] [python-mpd] 127/262: unicode encoded strings in python2 by default

Simon McVittie smcv at debian.org
Sun May 22 18:16:36 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 a6eec5f3c8ca1c28eaffba6aca49a1a9f9586af4
Author: Jörg Thalheim <jthalheim at gmail.com>
Date:   Thu Mar 29 22:11:42 2012 +0200

    unicode encoded strings in python2 by default
    
    to improve with old applications mpd.py now returns unicode encoded
    strings instead of unicode strings. It accepts unicode strings as well
    and have an option to return unicode strings.
    Sockets switched from binary to text mode.
    Using unicode strings is the prefered option because:
        a) mpd only accept utf-8 as input (there is just no choice)
        b) every application had to handle the encoding/decoding on its own
           before
---
 README.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++------------
 mpd.py    | 31 ++++++++++++++++++-------------
 test.py   | 25 +++++++++++++++++++++----
 3 files changed, 86 insertions(+), 29 deletions(-)

diff --git a/README.md b/README.md
index a274945..9741ab4 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ 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.
+
 Current features list:
 
  - python3 support (python2.6 is minimum python version required)
@@ -14,8 +16,7 @@ Current features list:
  - declare mpd commands explicit as method, so they are shown in ipython
  - add unit tests
  - documented API to add new commands (see Future Compatible)
- - expect and returns unicode strings in all commands instead of unicode encoded strings,
-   so use u"♥" instead of "♥" in python2 - no change in python3 as it use unicode strings by default
+ - use unicode strings in all commands instead of utf-8 encoded strings optionally in python2 and by default in python3 (see Unicode Handling)
 
 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/)
 
@@ -98,28 +99,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
 -----------------
 
diff --git a/mpd.py b/mpd.py
index 1765771..5bf177e 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,12 +24,13 @@ ERROR_PREFIX = "ACK "
 SUCCESS = "OK"
 NEXT = "list_OK"
 
-try:
-    # workaround to get unicode strings in all python versions
-    str = unicode
-except NameError:
-    pass
-
+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
@@ -162,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):
@@ -211,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")
@@ -356,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")
@@ -413,8 +418,8 @@ class MPDClient():
             self._sock = self._connect_unix(host)
         else:
             self._sock = self._connect_tcp(host, port)
-        self._rfile = self._sock.makefile("rb")
-        self._wfile = self._sock.makefile("wb")
+        self._rfile = self._sock.makefile("r")
+        self._wfile = self._sock.makefile("w")
         try:
             self._hello()
         except:
diff --git a/test.py b/test.py
index 124e333..c417f49 100755
--- a/test.py
+++ b/test.py
@@ -150,12 +150,29 @@ class TestMPDClient(unittest.TestCase):
                 "This either means the command list is wrong or mpd is not up-to-date."
         self.assertFalse(imple_cmds - avaible_cmds, long_desc)
 
-    def test_unicode_in_command_args(self):
+    def test_unicode_as_command_args(self):
         if sys.version_info < (3, 0):
-            arg = "☯☾☝♖✽".decode("utf-8")
+            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:
-            arg = "☯☾☝♖✽"
-        self.assertIsInstance(self.client.find("file",arg), list)
+            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)
 
 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