[PATCH] pwclient: Fix encoding problems

Robin Jarry robin.jarry at 6wind.com
Fri Dec 16 03:56:18 AEDT 2016


All data returned by the xmlrpc object is unicode decoded with 'utf-8' (on
python 3, unicode == str). Add from __future__ import unicode_literals
to make sure that everything is unicode and avoid surprises.

On python 2, printing unicode to stdout causes it to be encoded to str
(byte string) with the 'ascii' codec:

  >>> print some_unicode_string
  ...
  UnicodeEncodeError: 'ascii' codec can't encode character u'\u0142'
  in position 468: ordinal not in range(128)

Work around ths by avoiding any explicit call to unicode() and by
replacing sys.stdout and sys.stderr by unicode-aware file objects (as
returned by io.open()).

Guess the encoding of stdout and stderr by looking at (in that order):
sys.stdout.encoding, locale.getpreferredencoding(), the PYTHONIOENCODING
environment variable. If no encoding is defined, assume 'utf-8' as
output encoding.

Signed-off-by: Robin Jarry <robin.jarry at 6wind.com>
---
 patchwork/bin/pwclient | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/patchwork/bin/pwclient b/patchwork/bin/pwclient
index 7ea887802364..fee6366f36fe 100755
--- a/patchwork/bin/pwclient
+++ b/patchwork/bin/pwclient
@@ -21,6 +21,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from __future__ import print_function
+from __future__ import unicode_literals
 
 import os
 import sys
@@ -40,13 +41,17 @@ except ImportError:
     import configparser as ConfigParser
 import shutil
 import re
-
-# Add a shim for Python 2's unicode() helper.
-try:
-    unicode
-except NameError:
-    # Python 3 does everything by unicode now.
-    unicode = str
+import io
+import locale
+
+if sys.version_info.major == 2:
+    # hack to make writing unicode to standard output/error work on Python 2
+    OUT_ENCODING = sys.stdout.encoding or locale.getpreferredencoding() or \
+            os.getenv('PYTHONIOENCODING', 'utf-8')
+    sys.stdout = io.open(sys.stdout.fileno(), mode='w',
+                         encoding=OUT_ENCODING, errors='replace')
+    sys.stderr = io.open(sys.stderr.fileno(), mode='w',
+                         encoding=OUT_ENCODING, errors='replace')
 
 # Default Patchwork remote XML-RPC server URL
 # This script will check the PW_XMLRPC_URL environment variable
@@ -214,8 +219,7 @@ def action_list(rpc, filter, submitter_str, delegate_str, format_str=None):
             for id in ids:
                 person = rpc.person_get(id)
                 print('Patches submitted by %s <%s>:' %
-                      (unicode(person['name']).encode('utf-8'),
-                       unicode(person['email']).encode('utf-8')))
+                      (person['name'], person['email']))
                 f = filter
                 f.add("submitter_id", id)
                 patches = rpc.patch_list(f.d)
@@ -269,7 +273,7 @@ def action_check_info(rpc, check_id):
     print(s)
     print('-' * len(s))
     for key, value in sorted(check.items()):
-        print("- %- 14s: %s" % (key, unicode(value)))
+        print("- %- 14s: %s" % (key, value))
 
 
 def action_check_create(rpc, patch_id, context, state, url, description):
@@ -293,7 +297,7 @@ def action_info(rpc, patch_id):
     print(s)
     print('-' * len(s))
     for key, value in sorted(patch.items()):
-        print("- %- 14s: %s" % (key, unicode(value)))
+        print("- %- 14s: %s" % (key, value))
 
 
 def action_get(rpc, patch_id):
@@ -310,8 +314,8 @@ def action_get(rpc, patch_id):
         fname = "%s.%d" % (base_fname, i)
         i += 1
 
-    with open(fname, 'w') as f:
-        f.write(unicode(s))
+    with io.open(fname, 'w', encoding='utf-8') as f:
+        f.write(s)
         print('Saved patch to %s' % fname)
 
 
@@ -333,7 +337,7 @@ def action_apply(rpc, patch_id, apply_cmd=None):
     s = rpc.patch_get_mbox(patch_id)
     if len(s) > 0:
         proc = subprocess.Popen(apply_cmd, stdin=subprocess.PIPE)
-        proc.communicate(unicode(s).encode('utf-8'))
+        proc.communicate(s.encode('utf-8'))
         return proc.returncode
     else:
         sys.stderr.write("Error: No patch content found\n")
@@ -748,7 +752,7 @@ def main():
             for patch_id in non_empty(h, patch_ids):
                 s = rpc.patch_get_mbox(patch_id)
                 if len(s) > 0:
-                    i.append(unicode(s))
+                    i.append(s)
             if len(i) > 0:
                 pager.communicate(input="\n".join(i).encode("utf-8"))
             pager.stdin.close()
@@ -756,7 +760,7 @@ def main():
             for patch_id in non_empty(h, patch_ids):
                 s = rpc.patch_get_mbox(patch_id)
                 if len(s) > 0:
-                    print(unicode(s))
+                    print(s)
 
     elif action == 'info':
         for patch_id in non_empty(h, patch_ids):
-- 
2.1.4



More information about the Patchwork mailing list