Coverage for src/epublib/ncx/reset.py: 89%
46 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-18 16:07 -0300
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-18 16:07 -0300
1from pathlib import Path
3from bs4.element import NamespacedAttribute
5from epublib.exceptions import EPUBError
6from epublib.ncx.resource import NCXFile
7from epublib.package.metadata import ValuedMetadataItem
8from epublib.types import BookProtocol
10ncx_template = """<?xml version="1.0" encoding="UTF-8"?>
11<ncx version="2005-1" {lang_attr} xmlns="http://www.daisy.org/z3986/2005/ncx/">
12<head></head>
13<docTitle><text>{title}</text></docTitle>
14<navMap></navMap>
15</ncx
16"""
19def get_minimal_ncx_content(title: str, lang: str | None) -> bytes:
20 """
21 Get a minimal NCX file content with the given title and language.
22 Caution: the minimality of this template is in regard to the parsing
23 available in this library. To get a minimal valid NCX file, consider
24 using `EPUB.generate_ncx` instead.
25 """
26 if lang:
27 lang_attr = f'xml:lang="{lang}"'
28 else:
29 lang_attr = ""
30 return ncx_template.format(title=title, lang_attr=lang_attr).encode()
33def generate_ncx(book: BookProtocol, filename: str | Path | None = None) -> NCXFile:
34 if filename is None:
35 filename = book.base_dir / "toc.ncx"
37 if not book.metadata.title:
38 raise EPUBError("Can't generate NCX without book title in metadata")
40 if not (book.nav and book.nav.toc):
41 raise EPUBError("Can't generate NCX without Navigation Document with TOC")
43 if book.ncx is not None:
44 raise EPUBError(
45 "Can't generate NCX as it already exists. Try "
46 f"{book.__class__.__name__}.reset_ncx() instead"
47 )
49 ncx = NCXFile(
50 get_minimal_ncx_content(
51 book.metadata.title,
52 book.metadata.language,
53 ),
54 filename,
55 )
57 ncx = reset_ncx(book, ncx)
58 book.resources.add(ncx)
59 book.spine.tag["toc"] = book.manifest[ncx.filename].id
60 return ncx
63def reset_ncx(book: BookProtocol, ncx: NCXFile | None = None) -> NCXFile:
64 if not book.metadata.title:
65 raise EPUBError("Can't reset NCX without book title in metadata")
67 if not (book.nav and book.nav.toc):
68 raise EPUBError("Can't reset NCX without Navigation Document with TOC")
70 if ncx is None:
71 ncx = book.ncx
73 if ncx is None:
74 return generate_ncx(book)
76 ncx.title.text = book.metadata.title
77 creator = book.metadata.get("creator")
78 if isinstance(creator, ValuedMetadataItem):
79 __ = ncx.add_author(creator.value)
81 if book.metadata.language:
82 ncx.soup.ncx[NamespacedAttribute("xml", "lang")] = book.metadata.language
84 __ = ncx.sync_toc(book.nav)
85 if book.nav.page_list:
86 __ = ncx.sync_page_list(book.nav)
87 __ = ncx.sync_head(book.metadata)
89 return ncx