Repository: laterpay/laterpay-client-python

Issue:
Decode byte strings before using them during signing
On Python 3, when singing a request containing a byte string (`b'foo'`) the value is casted into a string, resulting in `"b'foo'"`, instead of properly decoding the string to `'foo'`.


Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/8301375/badge)](https://coveralls.io/builds/8301375)

Coverage increased (+0.03%) to 96.838% when pulling **24133bcd29248dc6ffe3b280de287fa99d356153 on bugfix/84** into **a4738be03b9cc0680d24466b7eefe5fdde6b7d2d on develop**.

suligap: Looks good. Could you add a relevant entry to the CHANGELOG please?
MarkusH: This might actually not finally solve the issue (need to look into it again), but we do some more casting in `sort_params()`. This needs to be reworked.
coveralls: 
[![Coverage Status](https://coveralls.io/builds/8321514/badge)](https://coveralls.io/builds/8321514)

Coverage decreased (-0.03%) to 96.787% when pulling **60c77ad543749d54ee27b625bc7d5dccc1828198 on bugfix/84** into **a4738be03b9cc0680d24466b7eefe5fdde6b7d2d on develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/8338167/badge)](https://coveralls.io/builds/8338167)

Coverage decreased (-0.03%) to 96.787% when pulling **5adc95c90fa7b86fd8debd47d347339963ec7ffc on bugfix/84** into **a4738be03b9cc0680d24466b7eefe5fdde6b7d2d on develop**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/8623388/badge)](https://coveralls.io/builds/8623388)

Coverage decreased (-0.03%) to 96.787% when pulling **820e3994a2eee44e93658ef588cdcf1739c88690 on bugfix/84** into **a4738be03b9cc0680d24466b7eefe5fdde6b7d2d on develop**.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8484c44..532fd0e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,11 @@
 # Changelog
 
 
-## Unreleased
+## 4.6.0 (under development)
+
+* Fixed encoding issues when passing byte string parameters on Python 3
+  ([#84](https://github.com/laterpay/laterpay-client-python/issues/84))
+
 
 ## 4.5.0
 
diff --git a/laterpay/signing.py b/laterpay/signing.py
index 24b1bf2..347aa31 100644
--- a/laterpay/signing.py
+++ b/laterpay/signing.py
@@ -53,12 +53,8 @@ def sort_params(param_dict):
     for name, value_list in six.iteritems(param_dict):
         if isinstance(value_list, (list, tuple)):
             for value in value_list:
-                if not isinstance(value, six.string_types):
-                    value = str(value)
                 param_list.append((name, value))
         else:
-            if not isinstance(value_list, six.string_types):
-                value_list = str(value_list)
             param_list.append((name, value_list))
 
     return sorted(param_list)
@@ -127,10 +123,13 @@ def create_base_message(params, url, method='POST'):
 
         values_str = []
 
-        # If any non six.string_types objects, ``str()`` them.
         for value in values:
-            if not isinstance(value, six.string_types):
+            if not isinstance(value, (six.string_types, six.binary_type)):
+                # If any non-string or non-bytes like objects, ``str()`` them.
                 value = str(value)
+            if six.PY3 and isinstance(value, six.binary_type):
+                # Issue #84, decode byte strings before using them on Python 3
+                value = value.decode()
             values_str.append(value)
 
         data[key] = [quote(compat.encode_if_unicode(value_str), safe='') for value_str in values_str]


Test patch:
diff --git a/tests/test_signing.py b/tests/test_signing.py
index ecbff1f..2f0fe02 100644
--- a/tests/test_signing.py
+++ b/tests/test_signing.py
@@ -25,7 +25,7 @@ class TestSigningHelper(unittest.TestCase):
         )
 
     def test_create_message_bytestrings(self):
-        params = {'parĄm1': 'valuĘ'}
+        params = {b'par\xc4\x84m1': b'valu\xc4\x98'}
         url = 'https://endpoint.com/ąpi'
 
         msg = signing.create_base_message(params, url)