Coverage for pyWebLayout/core/persistence.py: 90%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-08 20:34 +0000

1""" 

2Small JSON-file helpers shared by the per-document stores. 

3 

4BookmarkManager and HighlightManager both keep a JSON file per document under a 

5directory, and both had their own copy of "make the directory, try to read it, 

6swallow and print on failure". The duplication is the point of this module; the 

7file formats themselves stay owned by each store. 

8""" 

9 

10from __future__ import annotations 

11 

12import json 

13import logging 

14from pathlib import Path 

15from typing import Any 

16 

17logger = logging.getLogger(__name__) 

18 

19 

20def ensure_dir(path: str | Path) -> Path: 

21 """Return `path` as a Path, creating it and any missing parents.""" 

22 directory = Path(path) 

23 directory.mkdir(parents=True, exist_ok=True) 

24 return directory 

25 

26 

27def read_json(path: Path, default: Any) -> Any: 

28 """ 

29 Read JSON from `path`, returning `default` if it is missing or unreadable. 

30 

31 A corrupt store must not stop a book from opening, so failures are logged 

32 and swallowed. `default` is returned as given, so pass a fresh mutable if 

33 the caller intends to mutate it. 

34 """ 

35 if not path.exists(): 

36 return default 

37 

38 try: 

39 with open(path, 'r', encoding='utf-8') as handle: 

40 return json.load(handle) 

41 except (OSError, ValueError): 

42 logger.warning("Could not read %s; ignoring its contents", path, exc_info=True) 

43 return default 

44 

45 

46def write_json(path: Path, data: Any) -> bool: 

47 """ 

48 Write `data` to `path` as JSON. 

49 

50 Returns True on success. Failures are logged rather than raised: losing a 

51 bookmark is not a reason to take down the reader. 

52 """ 

53 try: 

54 with open(path, 'w', encoding='utf-8') as handle: 

55 json.dump(data, handle, indent=2) 

56 return True 

57 except (OSError, TypeError, ValueError): 

58 logger.error("Could not write %s", path, exc_info=True) 

59 return False