Skip to content

Commit 5d97f04

Browse files
Merge pull request #129 from NessieCanCode/improve-error-handling-in-_load_profile
Improve profile loading error handling
2 parents 293dc0b + 886019d commit 5d97f04

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

src/invoice.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import json
1212
import os
1313
import sys
14+
import logging
1415
from datetime import datetime
1516

1617
# Reportlab is required for PDF generation. If it's missing, emit a clear
@@ -38,8 +39,13 @@ def _load_profile(base_dir):
3839
try:
3940
with open(path, "r", encoding="utf-8") as fh:
4041
return json.load(fh)
41-
except Exception:
42+
except FileNotFoundError:
4243
return {}
44+
except json.JSONDecodeError as exc:
45+
logging.error("Failed to parse %s: %s", path, exc)
46+
except OSError as exc:
47+
logging.error("Unable to read %s: %s", path, exc)
48+
return {}
4349

4450

4551
def _profile_sections(profile):

test/check-application

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ PYTHONPATH=src python test/unit/billing_summary.test.py
1111
PYTHONPATH=src python test/unit/invoice_retrieval.test.py
1212
PYTHONPATH=src python test/unit/auth_boundaries.test.py
1313
PYTHONPATH=src python test/unit/accounts_listing.test.py
14+
PYTHONPATH=src python test/unit/profile_loading.test.py

test/unit/profile_loading.test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
import tempfile
3+
import unittest
4+
from unittest import mock
5+
import logging
6+
7+
from invoice import _load_profile
8+
9+
10+
class LoadProfileTests(unittest.TestCase):
11+
def test_missing_file_returns_empty_profile(self):
12+
with tempfile.TemporaryDirectory() as td:
13+
self.assertEqual(_load_profile(td), {})
14+
15+
def test_invalid_json_logs_error(self):
16+
with tempfile.TemporaryDirectory() as td:
17+
path = os.path.join(td, "institution.json")
18+
with open(path, "w", encoding="utf-8") as fh:
19+
fh.write("{invalid")
20+
with self.assertLogs(level="ERROR") as cm:
21+
self.assertEqual(_load_profile(td), {})
22+
self.assertIn("Failed to parse", cm.output[0])
23+
24+
def test_os_error_logs_error(self):
25+
with tempfile.TemporaryDirectory() as td:
26+
with mock.patch("builtins.open", side_effect=PermissionError("denied")):
27+
with self.assertLogs(level="ERROR") as cm:
28+
self.assertEqual(_load_profile(td), {})
29+
self.assertIn("Unable to read", cm.output[0])
30+
31+
32+
if __name__ == "__main__":
33+
unittest.main()

0 commit comments

Comments
 (0)