Coverage for src/epublib/nav/resource.py: 96%

74 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-18 16:07 -0300

1from pathlib import Path 

2from typing import IO, override 

3from zipfile import ZipInfo 

4 

5from epublib.mediatype import MediaType 

6from epublib.nav import LandmarksRoot, PageListRoot, TocRoot 

7from epublib.nav.util import LandmarkEntryData, PageBreakData, TOCEntryData 

8from epublib.resources import ContentDocument 

9from epublib.util import get_relative_href 

10 

11 

12class NavigationDocument(ContentDocument): 

13 """ 

14 A specialization of the XHTML content document that contains human- and 

15 machine-readable global navigation information. 

16 """ 

17 

18 def __init__( 

19 self, 

20 file: IO[bytes] | bytes, 

21 info: ZipInfo | str | Path, 

22 media_type: MediaType | str, 

23 ) -> None: 

24 super().__init__(file, info, media_type) 

25 self._toc: TocRoot | None = None 

26 self._page_list: PageListRoot | None = None 

27 self._landmarks: LandmarksRoot | None = None 

28 

29 def add_to_toc( 

30 self, 

31 filename: str, 

32 title: str, 

33 position: int | None = None, 

34 ): 

35 href = get_relative_href(self.filename, filename) 

36 

37 if self.toc is None: 

38 self._toc = TocRoot(self.soup, tag=None, base_filename=self.filename) 

39 

40 assert self.toc is not None 

41 return self.toc.add_item(href=href, text=title, position=position) 

42 

43 @property 

44 def toc(self): 

45 if self._toc is None: 

46 tag = self.soup.select_one('nav[epub|type="toc"]') 

47 if tag: 

48 self._toc = TocRoot(self.soup, tag, self.filename) 

49 return self._toc 

50 

51 @property 

52 def page_list(self): 

53 if self._page_list is None: 

54 tag = self.soup.select_one('nav[epub|type="page-list"]') 

55 if tag: 

56 self._page_list = PageListRoot(self.soup, tag, self.filename) 

57 return self._page_list 

58 

59 @property 

60 def landmarks(self): 

61 if self._landmarks is None: 

62 tag = self.soup.select_one('nav[epub|type="landmarks"]') 

63 if tag: 

64 self._landmarks = LandmarksRoot(self.soup, tag, self.filename) 

65 return self._landmarks 

66 

67 def reset_page_list(self, pagebreaks: list[PageBreakData]): 

68 if self.page_list is None: 

69 self._page_list = PageListRoot( 

70 self.soup, 

71 tag=None, 

72 base_filename=self.filename, 

73 ) 

74 

75 assert self.page_list 

76 self.page_list.reset(pagebreaks) 

77 

78 def reset_toc(self, entries: list[TOCEntryData]): 

79 if self.toc is None: 

80 self._toc = TocRoot(self.soup, tag=None, base_filename=self.filename) 

81 

82 assert self.toc 

83 self.toc.reset(entries) 

84 

85 def reset_landmarks(self, entries: list[LandmarkEntryData]): 

86 if self.landmarks is None: 

87 self._landmarks = LandmarksRoot( 

88 self.soup, 

89 tag=None, 

90 base_filename=self.filename, 

91 ) 

92 

93 assert self.landmarks 

94 self.landmarks.reset(entries) 

95 

96 def remove(self, filename: str): 

97 if self.toc: 

98 self.toc.remove(filename) 

99 if self.landmarks: 

100 self.landmarks.remove(filename) 

101 if self.page_list: 

102 self.page_list.remove(filename) 

103 

104 def on_soup_change(self): 

105 del self._toc 

106 del self._page_list 

107 del self._landmarks 

108 self._toc = None 

109 self._page_list = None 

110 self._landmarks = None 

111 

112 @override 

113 def on_content_change(self): 

114 super().on_content_change() 

115 self.on_soup_change()