From 92b617c238b61793874e3245062c278638d16bec Mon Sep 17 00:00:00 2001 From: ivan-holvi Date: Thu, 9 Jul 2026 16:21:23 +0200 Subject: [PATCH 1/2] fix: wrap non-JSON responses in EnableBankingException _request only wrapped HTTP errors (raise_for_status) into EnableBankingException. A successful status code with a non-JSON body (e.g. an empty 200 response) made response.json() raise requests' JSONDecodeError, which leaked to callers instead of being handled like any other request failure. Catch it and wrap it, attaching the response so callers can still inspect the status code. --- src/enablebanking_sdk/service/integration.py | 13 ++++++- tests/test_enablebanking_service.py | 38 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/enablebanking_sdk/service/integration.py b/src/enablebanking_sdk/service/integration.py index dff2bec..2d659dc 100644 --- a/src/enablebanking_sdk/service/integration.py +++ b/src/enablebanking_sdk/service/integration.py @@ -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 @@ -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", diff --git a/tests/test_enablebanking_service.py b/tests/test_enablebanking_service.py index 3482e4b..fd38af8 100644 --- a/tests/test_enablebanking_service.py +++ b/tests/test_enablebanking_service.py @@ -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 @@ -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) From 9d7f9640ae5660217ef94e30d55c778742a54804 Mon Sep 17 00:00:00 2001 From: ivan-holvi Date: Thu, 9 Jul 2026 16:21:23 +0200 Subject: [PATCH 2/2] chore: bump version to 0.1.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d337167..a2a7f99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ dynamic = [ "version" ] [tool.poetry] name = "enablebanking_sdk" -version = "0.1.6" +version = "0.1.7" description = "" authors = ["NOCFO "] license = "MIT"