Coverage for src/epublib/nav/resource.py: 100%
74 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-07 10:22 -0300
« prev ^ index » next coverage.py v7.10.7, created at 2025-10-07 10:22 -0300
1from pathlib import Path
2from typing import IO, override
3from zipfile import ZipInfo
5from epublib.exceptions import EPUBError
6from epublib.media_type import MediaType
7from epublib.nav import LandmarksRoot, PageListRoot, TocRoot
8from epublib.nav.util import LandmarkEntryData, PageBreakData, TOCEntryData
9from epublib.resources import ContentDocument
12class NavigationDocument(ContentDocument):
13 """
14 A specialization of the XHTML content document that contains human- and
15 machine-readable global navigation information.
16 """
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
29 @property
30 def toc(self) -> TocRoot:
31 if self._toc is None:
32 tag = self.soup.select_one('nav[epub|type="toc"]')
33 if tag:
34 self._toc = TocRoot.from_tag(self.soup, tag, own_filename=self.filename)
35 if not self._toc:
36 raise EPUBError("No TOC found in navigation document")
37 return self._toc
39 @property
40 def page_list(self):
41 if self._page_list is None:
42 tag = self.soup.select_one('nav[epub|type="page-list"]')
43 if tag:
44 self._page_list = PageListRoot.from_tag(
45 self.soup,
46 tag,
47 own_filename=self.filename,
48 )
49 return self._page_list
51 @property
52 def landmarks(self):
53 if self._landmarks is None:
54 tag = self.soup.select_one('nav[epub|type="landmarks"]')
55 if tag:
56 self._landmarks = LandmarksRoot.from_tag(
57 self.soup,
58 tag,
59 own_filename=self.filename,
60 )
61 return self._landmarks
63 def reset_page_list(self, pagebreaks: list[PageBreakData]):
64 if self.page_list is None:
65 self._page_list = PageListRoot(
66 self.soup,
67 own_filename=self.filename,
68 )
69 self._page_list.insert_self_in_soup()
71 assert self.page_list
72 self.page_list.reset(pagebreaks)
74 def reset_toc(self, entries: list[TOCEntryData]):
75 try:
76 _ = self.toc
77 except EPUBError:
78 self._toc = TocRoot(self.soup, own_filename=self.filename)
79 self._toc.insert_self_in_soup()
81 self.toc.reset(entries)
83 def reset_landmarks(self, entries: list[LandmarkEntryData]):
84 if self.landmarks is None:
85 self._landmarks = LandmarksRoot(
86 self.soup,
87 own_filename=self.filename,
88 )
89 self._landmarks.insert_self_in_soup()
91 assert self.landmarks
92 self.landmarks.reset(entries)
94 def remove(self, filename: str | Path):
95 if self.toc:
96 self.toc.remove_nodes(str(filename))
97 if self.landmarks:
98 self.landmarks.remove_all(filename)
99 if self.page_list:
100 self.page_list.remove_all(filename)
102 def on_soup_change(self):
103 del self._toc
104 del self._page_list
105 del self._landmarks
106 self._toc = None
107 self._page_list = None
108 self._landmarks = None
110 @override
111 def on_content_change(self):
112 super().on_content_change()
113 self.on_soup_change()