Skip to content

Commit

Permalink
Allow more control over exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
Colin-b committed Jun 18, 2024
1 parent cc90b26 commit 19b6557
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The authentication success and failure displayed in the browser were revamped to be more user-friendly. `requests_auth.testing` was modified to accommodate this change:
- `tab.assert_success` `expected_message` parameter was removed.
- `tab.assert_failure` `expected_message` parameter should not be prefixed with `Unable to properly perform authentication: ` anymore and `\n` in the message should be replaced with `<br>`.
- Exceptions issued by `requests_auth` are now inheriting from `requests_auth.RequestsAuthException`, itself inheriting from `requests.RequestException`, instead of `Exception`.

### Fixed
- Type information is now provided following [PEP 561](https://www.python.org/dev/peps/pep-0561/).
Expand Down
2 changes: 2 additions & 0 deletions requests_auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
InvalidToken,
TokenExpiryNotProvided,
InvalidGrantRequest,
RequestsAuthException,
)
from requests_auth.version import __version__

Expand Down Expand Up @@ -67,6 +68,7 @@
"SupportMultiAuth",
"JsonTokenFileCache",
"TokenMemoryCache",
"RequestsAuthException",
"GrantNotProvided",
"TimeoutOccurred",
"AuthenticationFailed",
Expand Down
35 changes: 20 additions & 15 deletions requests_auth/_errors.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
from json import JSONDecodeError
from typing import Union

from requests import Response
from requests import Response, RequestException


class AuthenticationFailed(Exception):
class RequestsAuthException(RequestException): ...


class AuthenticationFailed(RequestsAuthException):
"""User was not authenticated."""

def __init__(self):
Exception.__init__(self, "User was not authenticated.")
RequestsAuthException.__init__(self, "User was not authenticated.")


class TimeoutOccurred(Exception):
class TimeoutOccurred(RequestsAuthException):
"""No response within timeout interval."""

def __init__(self, timeout: float):
Exception.__init__(
RequestsAuthException.__init__(
self, f"User authentication was not received within {timeout} seconds."
)


class InvalidToken(Exception):
class InvalidToken(RequestsAuthException):
"""Token is invalid."""

def __init__(self, token_name: str):
Exception.__init__(self, f"{token_name} is invalid.")
RequestsAuthException.__init__(self, f"{token_name} is invalid.")


class GrantNotProvided(Exception):
class GrantNotProvided(RequestsAuthException):
"""Grant was not provided."""

def __init__(self, grant_name: str, dictionary_without_grant: dict):
Exception.__init__(
RequestsAuthException.__init__(
self, f"{grant_name} not provided within {dictionary_without_grant}."
)


class InvalidGrantRequest(Exception):
class InvalidGrantRequest(RequestsAuthException):
"""
If the request failed client authentication or is invalid, the authorization server returns an error response as described in https://tools.ietf.org/html/rfc6749#section-5.2
"""
Expand Down Expand Up @@ -64,7 +67,7 @@ class InvalidGrantRequest(Exception):
}

def __init__(self, response: Union[Response, dict]):
Exception.__init__(self, InvalidGrantRequest.to_message(response))
RequestsAuthException.__init__(self, InvalidGrantRequest.to_message(response))

@staticmethod
def to_message(response: Union[Response, dict]) -> str:
Expand Down Expand Up @@ -114,17 +117,19 @@ def _pop(key: str) -> str:
return message


class StateNotProvided(Exception):
class StateNotProvided(RequestsAuthException):
"""State was not provided."""

def __init__(self, dictionary_without_state: dict):
Exception.__init__(
RequestsAuthException.__init__(
self, f"state not provided within {dictionary_without_state}."
)


class TokenExpiryNotProvided(Exception):
class TokenExpiryNotProvided(RequestsAuthException):
"""Token expiry was not provided."""

def __init__(self, token_body: dict):
Exception.__init__(self, f"Expiry (exp) is not provided in {token_body}.")
RequestsAuthException.__init__(
self, f"Expiry (exp) is not provided in {token_body}."
)
3 changes: 3 additions & 0 deletions tests/features/token_cache/test_json_token_file_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import pytest
import jwt
import requests

import requests_auth
import requests_auth._oauth2.tokens
Expand Down Expand Up @@ -78,6 +79,8 @@ def failing_dump(*args):
with pytest.raises(requests_auth.AuthenticationFailed) as exception_info:
same_cache.get_token("key1")
assert str(exception_info.value) == "User was not authenticated."
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)

assert caplog.messages == [
"Cannot save tokens.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,12 @@ def test_oauth2_authorization_code_flow_uses_custom_failure(
displayed_html="FAILURE: {display_time}\n{information}",
)

with pytest.raises(requests_auth.InvalidGrantRequest):
with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info:
requests.get("http://authorized_only", auth=auth)

assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)

tab.assert_failure(
"invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."
)
Expand Down Expand Up @@ -478,6 +481,8 @@ def test_empty_token_is_invalid(
str(exception_info.value)
== "access_token not provided within {'access_token': '', 'token_type': 'example', 'expires_in': 3600, 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA', 'example_parameter': 'example_value'}."
)
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)
tab.assert_success()


Expand Down
8 changes: 8 additions & 0 deletions tests/oauth2/implicit/test_oauth2_implicit.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ def open(self, url, new):
str(exception_info.value)
== "User authentication was not received within 0.1 seconds."
)
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)


def test_browser_error(token_cache, responses: RequestsMock, monkeypatch):
Expand Down Expand Up @@ -371,6 +373,8 @@ def test_empty_token_is_invalid(token_cache, browser_mock: BrowserMock):
auth=requests_auth.OAuth2Implicit("http://provide_token"),
)
assert str(exception_info.value) == " is invalid."
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)
tab.assert_success()


Expand All @@ -386,6 +390,8 @@ def test_token_without_expiry_is_invalid(token_cache, browser_mock: BrowserMock)
auth=requests_auth.OAuth2Implicit("http://provide_token"),
)
assert str(exception_info.value) == "Expiry (exp) is not provided in None."
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)
tab.assert_success()


Expand Down Expand Up @@ -612,6 +618,8 @@ def test_oauth2_implicit_flow_post_failure_if_state_is_not_provided(
str(exception_info.value)
== f"state not provided within {{'access_token': ['{token}']}}."
)
assert isinstance(exception_info.value, requests_auth.RequestsAuthException)
assert isinstance(exception_info.value, requests.RequestException)
tab.assert_failure(f"state not provided within {{'access_token': ['{token}']}}.")


Expand Down

0 comments on commit 19b6557

Please sign in to comment.