Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion tests/test_errors.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
"""unit tests to define behavior of custom exception types"""
from unittest.mock import MagicMock

from trakt.errors import (BadRequestException, ConflictException,
ForbiddenException, NotFoundException,
OAuthException, ProcessException, RateLimitException,
OAuthException, OAuthRefreshException,
ProcessException, RateLimitException,
TraktException, TraktInternalException,
TraktUnavailable)

Expand Down Expand Up @@ -74,3 +77,51 @@ def test_503_exception():
assert texc.http_code == 503
assert texc.message == 'Trakt Unavailable - server overloaded'
assert str(texc) == texc.message


def test_oauth_refresh_exception_default_str():
texc = OAuthRefreshException()
assert str(texc) == 'Unauthorized - OAuth token refresh failed'


def test_oauth_refresh_exception_from_response_json():
response = MagicMock()
response.json.return_value = {'error': 'invalid_grant', 'error_description': 'Token has expired'}
texc = OAuthRefreshException(response=response)
assert texc.error == 'invalid_grant'
assert texc.error_description == 'Token has expired'
assert str(texc) == 'Unauthorized - OAuth token refresh failed: invalid_grant - Token has expired'


def test_oauth_refresh_exception_explicit_args_override_response():
response = MagicMock()
response.json.return_value = {'error': 'from_response', 'error_description': 'from_response_desc'}
texc = OAuthRefreshException(response=response, error='explicit_error', error_description='explicit_desc')
assert texc.error == 'explicit_error'
assert texc.error_description == 'explicit_desc'


def test_oauth_refresh_exception_no_response():
texc = OAuthRefreshException(response=None)
assert texc.error is None
assert texc.error_description is None
assert str(texc) == 'Unauthorized - OAuth token refresh failed'


def test_oauth_refresh_exception_json_raises():
response = MagicMock()
response.json.side_effect = ValueError('not json')
texc = OAuthRefreshException(response=response)
assert texc.error is None
assert texc.error_description is None


def test_oauth_refresh_exception_error_only_str():
texc = OAuthRefreshException(error='invalid_client')
assert str(texc) == 'Unauthorized - OAuth token refresh failed: invalid_client'


def test_oauth_refresh_exception_cause():
cause = RuntimeError('original')
texc = OAuthRefreshException(cause=cause)
assert texc.cause is cause
34 changes: 30 additions & 4 deletions trakt/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,43 @@ class OAuthException(TraktException):


class OAuthRefreshException(OAuthException):
def __init__(self, response=None):
"""Raised when an OAuth access token could not be refreshed."""

message = 'Unauthorized - OAuth token refresh failed'

def __init__(self, response=None, error=None, error_description=None, cause=None):
super().__init__(response)
self.data = self.response.json()
self.cause = cause
data = self._load_data()
self._error = error if error is not None else data.get("error")
self._error_description = error_description if error_description is not None else data.get("error_description")

def _load_data(self):
from json import JSONDecodeError
if self.response is None:
return {}
try:
data = self.response.json()
except (ValueError, JSONDecodeError, AttributeError):
return {}
if not isinstance(data, dict):
return {}
return data

@property
def error(self):
return self.data["error"]
return self._error

@property
def error_description(self):
return self.data["error_description"]
return self._error_description

def __str__(self):
if self._error and self._error_description:
return f'{self.message}: {self._error} - {self._error_description}'
if self._error:
return f'{self.message}: {self._error}'
return self.message


class ForbiddenException(TraktException):
Expand Down