Repository: auth0/auth0-python
Pull request #99 (2018-04-27 19:09:06)

Perform release 3.2.0


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d3cda9..ba9d50c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
 Changes
 =======
 
+3.2.0
+------------------
+
+Authentication API
+- Better error handling.
+
+Management API
+- Better error handling.
+- Fix inconsistence where UserBlocks required to be instantiated by the user.
+
 3.1.4
 ------------------
 
diff --git a/auth0/__init__.py b/auth0/__init__.py
index a7f6b6d..573cf70 100644
--- a/auth0/__init__.py
+++ b/auth0/__init__.py
@@ -1,1 +1,1 @@
-__version__ = '3.1.4'
+__version__ = '3.2.0'
diff --git a/auth0/v3/authentication/base.py b/auth0/v3/authentication/base.py
index 7f9eb3d..7d466b3 100644
--- a/auth0/v3/authentication/base.py
+++ b/auth0/v3/authentication/base.py
@@ -2,10 +2,8 @@ import json
 import requests
 from ..exceptions import Auth0Error
 
-
 UNKNOWN_ERROR = 'a0.sdk.internal.unknown'
 
-
 class AuthenticationBase(object):
 
     def post(self, url, data=None, headers=None):
@@ -27,7 +25,6 @@ class AuthenticationBase(object):
         except ValueError:
             return PlainResponse(response)
 
-
 class Response(object):
     def __init__(self, status_code, content):
         self._status_code = status_code
@@ -44,18 +41,10 @@ class Response(object):
     def _is_error(self):
         return self._status_code is None or self._status_code >= 400
 
-    # Adding these methods to force implementation in subclasses because they are references in this parent class
-    def _error_code(self):
-        raise NotImplementedError
-
-    def _error_message(self):
-        raise NotImplementedError
-
-
 class JsonResponse(Response):
     def __init__(self, response):
         content = json.loads(response.text)
-        super(JsonResponse, self).__init__(response.status_code, content)
+        super().__init__(response.status_code, content)
 
     def _error_code(self):
         if 'error' in self._content:
@@ -68,10 +57,9 @@ class JsonResponse(Response):
     def _error_message(self):
         return self._content.get('error_description', '')
 
-
 class PlainResponse(Response):
     def __init__(self, response):
-        super(PlainResponse, self).__init__(response.status_code, response.text)
+        super().__init__(response.status_code, response.text)
 
     def _error_code(self):
         return UNKNOWN_ERROR
@@ -79,10 +67,9 @@ class PlainResponse(Response):
     def _error_message(self):
         return self._content
 
-
 class EmptyResponse(Response):
     def __init__(self, status_code):
-        super(EmptyResponse, self).__init__(status_code, '')
+        super().__init__(status_code, '')
 
     def _error_code(self):
         return UNKNOWN_ERROR
diff --git a/auth0/v3/management/auth0.py b/auth0/v3/management/auth0.py
index cc94a89..3996cd2 100644
--- a/auth0/v3/management/auth0.py
+++ b/auth0/v3/management/auth0.py
@@ -40,4 +40,4 @@ class Auth0(object):
         self.guardian = Guardian(domain, token)
         self.logs = Logs(domain, token)
         self.resource_servers = ResourceServers(domain, token)
-        self.user_blocks = UserBlocks(domain, token)
+        self.user_blocks = UserBlocks
diff --git a/auth0/v3/management/rest.py b/auth0/v3/management/rest.py
index 9ff7626..eed23fa 100644
--- a/auth0/v3/management/rest.py
+++ b/auth0/v3/management/rest.py
@@ -5,9 +5,6 @@ import requests
 from ..exceptions import Auth0Error
 
 
-UNKNOWN_ERROR = 'a0.sdk.internal.unknown'
-
-
 class RestClient(object):
 
     """Provides simple methods for handling all RESTful api endpoints. """
@@ -106,71 +103,10 @@ class RestClient(object):
         return self._process_response(response)
 
     def _process_response(self, response):
-        return self._parse(response).content()
-
-    def _parse(self, response):
-        if not response.text:
-            return EmptyResponse(response.status_code)
-        try:
-            return JsonResponse(response)
-        except ValueError:
-            return PlainResponse(response)
-
-class Response(object):
-    def __init__(self, status_code, content):
-        self._status_code = status_code
-        self._content = content
-
-    def content(self):
-        if self._is_error():
-            raise Auth0Error(status_code=self._status_code,
-                             error_code=self._error_code(),
-                             message=self._error_message())
-        else:
-            return self._content
-
-    def _is_error(self):
-        return self._status_code is None or self._status_code >= 400
-
-    # Adding these methods to force implementation in subclasses because they are references in this parent class
-    def _error_code(self):
-        raise NotImplementedError
-
-    def _error_message(self):
-        raise NotImplementedError
-
-class JsonResponse(Response):
-    def __init__(self, response):
-        content = json.loads(response.text)
-        super(JsonResponse, self).__init__(response.status_code, content)
-
-    def _error_code(self):
-        if 'errorCode' in self._content:
-            return self._content.get('errorCode')
-        elif 'error' in self._content:
-            return self._content.get('error')
-        else:
-            return UNKNOWN_ERROR
-
-    def _error_message(self):
-        return self._content.get('error', self._content.get('message', ''))
-
-class PlainResponse(Response):
-    def __init__(self, response):
-        super(PlainResponse, self).__init__(response.status_code, response.text)
-
-    def _error_code(self):
-        return UNKNOWN_ERROR
-
-    def _error_message(self):
-        return self._content
-
-class EmptyResponse(Response):
-    def __init__(self, status_code):
-        super(EmptyResponse, self).__init__(status_code, '')
-
-    def _error_code(self):
-        return UNKNOWN_ERROR
+        text = json.loads(response.text) if response.text else {}
 
-    def _error_message(self):
-        return ''
+        if isinstance(text, dict) and 'errorCode' in text:
+            raise Auth0Error(status_code=text['statusCode'],
+                             error_code=text['errorCode'],
+                             message=text['message'])
+        return text


Test patch:
diff --git a/auth0/v3/test/management/test_rest.py b/auth0/v3/test/management/test_rest.py
index 6a7418b..b173b3d 100644
--- a/auth0/v3/test/management/test_rest.py
+++ b/auth0/v3/test/management/test_rest.py
@@ -13,7 +13,6 @@ class TestRest(unittest.TestCase):
         headers = {'Authorization': 'Bearer a-token'}
 
         mock_get.return_value.text = '["a", "b"]'
-        mock_get.return_value.status_code = 200
 
         response = rc.get('the-url')
         mock_get.assert_called_with('the-url', params={}, headers=headers)
@@ -28,7 +27,7 @@ class TestRest(unittest.TestCase):
 
         mock_get.return_value.text = ''
         response = rc.get('the/url')
-        self.assertEqual(response, '')
+        self.assertEqual(response, {})
 
     @mock.patch('requests.get')
     def test_get_errors(self, mock_get):
@@ -38,7 +37,6 @@ class TestRest(unittest.TestCase):
         mock_get.return_value.text = '{"statusCode": 999,' \
                                      ' "errorCode": "code",' \
                                      ' "message": "message"}'
-        mock_get.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.get('the/url')
@@ -57,7 +55,6 @@ class TestRest(unittest.TestCase):
 
         data = {'some': 'data'}
 
-        mock_post.return_value.status_code = 200
         response = rc.post('the/url', data=data)
         mock_post.assert_called_with('the/url', data=json.dumps(data),
                                      headers=headers)
@@ -71,7 +68,6 @@ class TestRest(unittest.TestCase):
         mock_post.return_value.text = '{"statusCode": 999,' \
                                       ' "errorCode": "code",' \
                                       ' "message": "message"}'
-        mock_post.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.post('the-url')
@@ -80,68 +76,6 @@ class TestRest(unittest.TestCase):
         self.assertEqual(context.exception.error_code, 'code')
         self.assertEqual(context.exception.message, 'message')
 
-    @mock.patch('requests.post')
-    def test_post_error_with_code_property(self, mock_post):
-        rc = RestClient(jwt='a-token', telemetry=False)
-
-        for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"errorCode": "e0",' \
-                                          '"message": "desc"}'
-
-            with self.assertRaises(Auth0Error) as context:
-                rc.post('the-url')
-
-            self.assertEqual(context.exception.status_code, error_status)
-            self.assertEqual(context.exception.error_code, 'e0')
-            self.assertEqual(context.exception.message, 'desc')
-
-    @mock.patch('requests.post')
-    def test_post_error_with_no_error_code(self, mock_post):
-        rc = RestClient(jwt='a-token', telemetry=False)
-
-        for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = '{"message": "desc"}'
-
-            with self.assertRaises(Auth0Error) as context:
-                rc.post('the-url')
-
-            self.assertEqual(context.exception.status_code, error_status)
-            self.assertEqual(context.exception.error_code, 'a0.sdk.internal.unknown')
-            self.assertEqual(context.exception.message, 'desc')
-
-    @mock.patch('requests.post')
-    def test_post_error_with_text_response(self, mock_post):
-        rc = RestClient(jwt='a-token', telemetry=False)
-
-        for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = 'there has been a terrible error'
-
-            with self.assertRaises(Auth0Error) as context:
-                rc.post('the-url')
-
-            self.assertEqual(context.exception.status_code, error_status)
-            self.assertEqual(context.exception.error_code, 'a0.sdk.internal.unknown')
-            self.assertEqual(context.exception.message,
-                             'there has been a terrible error')
-
-    @mock.patch('requests.post')
-    def test_post_error_with_no_response_text(self, mock_post):
-        rc = RestClient(jwt='a-token', telemetry=False)
-
-        for error_status in [400, 500, None]:
-            mock_post.return_value.status_code = error_status
-            mock_post.return_value.text = None
-
-            with self.assertRaises(Auth0Error) as context:
-                rc.post('the-url')
-
-            self.assertEqual(context.exception.status_code, error_status)
-            self.assertEqual(context.exception.error_code, 'a0.sdk.internal.unknown')
-            self.assertEqual(context.exception.message, '')
-
     @mock.patch('requests.patch')
     def test_patch(self, mock_patch):
         rc = RestClient(jwt='a-token', telemetry=False)
@@ -149,7 +83,6 @@ class TestRest(unittest.TestCase):
                    'Content-Type': 'application/json'}
 
         mock_patch.return_value.text = '["a", "b"]'
-        mock_patch.return_value.status_code = 200
 
         data = {'some': 'data'}
 
@@ -166,7 +99,6 @@ class TestRest(unittest.TestCase):
         mock_patch.return_value.text = '{"statusCode": 999,' \
                                        ' "errorCode": "code",' \
                                        ' "message": "message"}'
-        mock_patch.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.patch(url='the/url')
@@ -181,7 +113,6 @@ class TestRest(unittest.TestCase):
         headers = {'Authorization': 'Bearer a-token'}
 
         mock_delete.return_value.text = '["a", "b"]'
-        mock_delete.return_value.status_code = 200
 
         response = rc.delete(url='the-url/ID')
         mock_delete.assert_called_with('the-url/ID', headers=headers, params={})
@@ -195,7 +126,6 @@ class TestRest(unittest.TestCase):
         mock_delete.return_value.text = '{"statusCode": 999,' \
                                         ' "errorCode": "code",' \
                                         ' "message": "message"}'
-        mock_delete.return_value.status_code = 999
 
         with self.assertRaises(Auth0Error) as context:
             rc.delete(url='the-url')