Repository: shaarli/python-shaarli-client

Issue:
Traceback error ( AttributeError: 'str' object has no attribute 'decode')
Python 3.7.3

When I enter `shaarli get-info` (or really any valid command) I get this:

Traceback (most recent call last):
  File "/home/pi/.virtualenvs/shaarli/bin/shaarli", line 10, in <module>
    sys.exit(main())
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/shaarli_client/main.py", line 58, in main
    response = ShaarliV1Client(url, secret).request(args)
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/shaarli_client/client/v1.py", line 267, in request
    return self._request(* self._retrieve_http_params(args))
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/shaarli_client/client/v1.py", line 261, in _request
    params=params
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests/api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests/sessions.py", line 528, in request
    prep = self.prepare_request(req)
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests/sessions.py", line 466, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests/models.py", line 320, in prepare
    self.prepare_auth(auth, url)
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests/models.py", line 551, in prepare_auth
    r = auth(self)
  File "/home/pi/.virtualenvs/shaarli/lib/python3.7/site-packages/requests_jwt/__init__.py", line 165, in __call__
    request.headers['Authorization'] = self._header_format % token.decode('ascii')
AttributeError: 'str' object has no attribute 'decode'

I do have the correct secret and URL of my instance.


Discussion:

Patch:
diff --git a/setup.py b/setup.py
index 5044848..404b2e5 100644
--- a/setup.py
+++ b/setup.py
@@ -40,9 +40,8 @@ setup(
         ],
     },
     install_requires=[
-        'requests >= 2.10',
-        'requests-jwt >= 0.4, < 0.5',
-        'pyjwt == 1.7.1'
+        'requests >= 2.25',
+        'pyjwt == 2.0.1'
     ],
     classifiers=[
         'Development Status :: 3 - Alpha',
diff --git a/shaarli_client/client/v1.py b/shaarli_client/client/v1.py
index 59b0b93..2113abe 100644
--- a/shaarli_client/client/v1.py
+++ b/shaarli_client/client/v1.py
@@ -3,8 +3,8 @@ import calendar
 import time
 from argparse import Action, ArgumentTypeError
 
+import jwt
 import requests
-from requests_jwt import JWTAuth
 
 
 def check_positive_integer(value):
@@ -248,8 +248,12 @@ class ShaarliV1Client:
 
     def _request(self, method, endpoint, params, verify_certs=True):
         """Send an HTTP request to this instance"""
-        auth = JWTAuth(self.secret, alg='HS512', header_format='Bearer %s')
-        auth.add_field('iat', lambda req: calendar.timegm(time.gmtime()))
+        encoded_token = jwt.encode(
+            {'iat': calendar.timegm(time.gmtime())},
+            self.secret,
+            algorithm='HS512',
+        )
+        headers = {'Authorization': 'Bearer %s' % encoded_token}
 
         endpoint_uri = '%s/api/v%d/%s' % (self.uri, self.version, endpoint)
 
@@ -257,11 +261,16 @@ class ShaarliV1Client:
             return requests.request(
                 method,
                 endpoint_uri,
-                auth=auth,
+                headers=headers,
                 params=params,
                 verify=verify_certs
             )
-        return requests.request(method, endpoint_uri, auth=auth, json=params)
+        return requests.request(
+            method,
+            endpoint_uri,
+            headers=headers,
+            json=params,
+        )
 
     def request(self, args):
         """Send a parameterized request to this instance"""


Test patch:
diff --git a/tests/client/test_v1.py b/tests/client/test_v1.py
index a08f239..9abee4f 100644
--- a/tests/client/test_v1.py
+++ b/tests/client/test_v1.py
@@ -119,7 +119,7 @@ def test_get_info_uri(request):
     request.assert_called_once_with(
         'GET',
         '%s/api/v1/info' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         verify=True,
         params={}
     )
@@ -145,7 +145,7 @@ def test_get_links_uri(request):
     request.assert_called_once_with(
         'GET',
         '%s/api/v1/links' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         verify=True,
         params={}
     )
@@ -187,7 +187,7 @@ def test_post_links_uri(request):
     request.assert_called_once_with(
         'POST',
         '%s/api/v1/links' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         json={}
     )
 
@@ -229,7 +229,7 @@ def test_put_links_uri(request):
     request.assert_called_once_with(
         'PUT',
         '%s/api/v1/links/12' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         json={}
     )
 
@@ -288,7 +288,7 @@ def test_get_tags_uri(request):
     request.assert_called_once_with(
         'GET',
         '%s/api/v1/tags' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         verify=True,
         params={}
     )
@@ -301,7 +301,7 @@ def test_put_tags_uri(request):
     request.assert_called_once_with(
         'PUT',
         '%s/api/v1/tags/some-tag' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         json={}
     )
 
@@ -340,7 +340,7 @@ def test_delete_tags_uri(request):
     request.assert_called_once_with(
         'DELETE',
         '%s/api/v1/tags/some-tag' % SHAARLI_URL,
-        auth=mock.ANY,
+        headers=mock.ANY,
         json={}
     )