Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ dynamic = [ "version" ]

[tool.poetry]
name = "enablebanking_sdk"
version = "0.1.6"
version = "0.1.7"
description = ""
authors = ["NOCFO <team@nocfo.io>"]
license = "MIT"
Expand Down
13 changes: 12 additions & 1 deletion src/enablebanking_sdk/service/integration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
from datetime import datetime, timedelta
from typing import Tuple
from requests.exceptions import HTTPError
from requests.exceptions import HTTPError, JSONDecodeError

import jwt
import requests
Expand Down Expand Up @@ -104,6 +104,17 @@ def _request(
response=err.response,
) from err

except JSONDecodeError as err:
# A successful status code with a non-JSON body (e.g. an empty 200
# response) still leaves callers with nothing usable. Surface it as an
# EnableBankingException so it is handled like any other request failure
# instead of leaking a raw JSONDecodeError.
raise EnableBankingException(
err,
request=response.request,
response=response,
) from err

def get_aspsps(self, country: str, psu_type: str) -> dict:
return self._request(
method="GET",
Expand Down
38 changes: 38 additions & 0 deletions tests/test_enablebanking_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
from datetime import date, datetime
from unittest import mock

import requests

from src.enablebanking_sdk.constants import PSUType
from src.enablebanking_sdk.constants.transaction_fetch_strategy import (
TransactionsFetchStrategy,
)
from src.enablebanking_sdk.exceptions import EnableBankingException
from src.enablebanking_sdk.models import AspspData
from src.enablebanking_sdk.service import EnableBankingService, EnableBankingIntegration
from tests.utils import get_json_fixtures
Expand Down Expand Up @@ -124,3 +127,38 @@ def test_get_account_details(self, request_mock):
)

self.assertEqual(data.details, "My account nickname")

@mock.patch.object(
EnableBankingIntegration, "_get_token", return_value="mock-token"
)
@mock.patch("src.enablebanking_sdk.service.integration.requests.request")
def test_request_wraps_non_json_body_as_enablebanking_exception(
self, request_mock, _token_mock
):
response = requests.Response()
response.status_code = 200
response._content = b"" # empty body -> response.json() raises JSONDecodeError
request_mock.return_value = response

with self.assertRaises(EnableBankingException) as ctx:
self.service.integration._request(method="GET", path="/accounts/x/balances")

# The originating response is attached so callers can still inspect the status code.
self.assertEqual(ctx.exception.response.status_code, 200)

@mock.patch.object(
EnableBankingIntegration, "_get_token", return_value="mock-token"
)
@mock.patch("src.enablebanking_sdk.service.integration.requests.request")
def test_request_wraps_http_error_as_enablebanking_exception(
self, request_mock, _token_mock
):
response = requests.Response()
response.status_code = 500
response._content = b"Internal Server Error"
request_mock.return_value = response

with self.assertRaises(EnableBankingException) as ctx:
self.service.integration._request(method="GET", path="/accounts/x/balances")

self.assertEqual(ctx.exception.response.status_code, 500)
Loading