From bebb92175502d1487018a48fa8665ad4bdafbf95 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 06:20:23 +0000 Subject: [PATCH] docs: Add API documentation with docstrings Adds comprehensive RST-formatted docstrings to all public classes and methods to improve API clarity and usability for developers. Closes #13 --- src/imposition/book.py | 23 +++++++++++++++++++ src/imposition/exceptions.py | 20 ++++++++++++++--- src/imposition/rendition.py | 43 +++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/imposition/book.py b/src/imposition/book.py index 79cba08..74f4e5a 100644 --- a/src/imposition/book.py +++ b/src/imposition/book.py @@ -6,10 +6,26 @@ from .exceptions import InvalidEpubError, MissingContainerError + class Book: + """ + Parses and provides access to the contents of an EPUB file. + + This class takes the binary content of an EPUB file, parses its + structure, and provides methods to access its table of contents and + spine. + """ + def __init__(self, epub_bytes: bytes) -> None: """ Initializes the Book object from a bytes object of the EPUB file. + + :param epub_bytes: The binary content of the EPUB file. + :type epub_bytes: bytes + :raises InvalidEpubError: If the file is not a valid ZIP archive or if + the EPUB structure is invalid. + :raises MissingContainerError: If the META-INF/container.xml file is + not found. """ epub_file = io.BytesIO(epub_bytes) try: @@ -55,6 +71,13 @@ def __init__(self, epub_bytes: bytes) -> None: self.toc: List[Dict[str, str]] = self._parse_toc() def get_toc(self) -> List[Dict[str, str]]: + """ + Returns the table of contents. + + :return: A list of dictionaries, where each dictionary represents a + table of contents item with 'title' and 'url' keys. + :rtype: List[Dict[str, str]] + """ return self.toc def _parse_toc(self) -> List[Dict[str, str]]: diff --git a/src/imposition/exceptions.py b/src/imposition/exceptions.py index d626138..bab801c 100644 --- a/src/imposition/exceptions.py +++ b/src/imposition/exceptions.py @@ -1,11 +1,25 @@ class ImpositionError(Exception): - """Base class for exceptions in this module.""" + """Base class for all exceptions raised by the imposition library.""" + pass + class InvalidEpubError(ImpositionError): - """Exception raised for errors in the EPUB file format.""" + """ + Exception raised for errors related to the EPUB file format. + + This can include issues with the ZIP structure, XML parsing, or missing + required components in the EPUB container. + """ + pass + class MissingContainerError(InvalidEpubError): - """Exception raised when META-INF/container.xml is missing.""" + """ + Exception raised when the META-INF/container.xml file is missing. + + This file is essential for locating the root OPF file of the EPUB. + """ + pass diff --git a/src/imposition/rendition.py b/src/imposition/rendition.py index 3ed1095..ad6aeab 100644 --- a/src/imposition/rendition.py +++ b/src/imposition/rendition.py @@ -11,8 +11,25 @@ if TYPE_CHECKING: from .book import Book + class Rendition: + """ + Renders an EPUB file into a web-based reader interface. + + This class handles the display of the EPUB's table of contents and + chapters, and provides navigation between them. + """ + def __init__(self, book: Book, target_id: str) -> None: + """ + Initializes the Rendition object. + + :param book: An initialized Book object. + :type book: Book + :param target_id: The ID of the HTML element where the EPUB content + will be rendered. + :type target_id: str + """ self.book: Book = book self.target_id: str = target_id self.target_element: JsProxy = document.getElementById(self.target_id) @@ -23,6 +40,9 @@ def __init__(self, book: Book, target_id: str) -> None: self.iframe.style.border = 'none' def display_toc(self) -> None: + """ + Renders the table of contents into the 'toc-container' element. + """ toc_container: JsProxy = document.getElementById('toc-container') toc_container.innerHTML = '' ul: JsProxy = document.createElement('ul') @@ -50,9 +70,18 @@ def handler(event: JsProxy) -> None: def display(self, chapter_url: Optional[str] = None) -> None: + """ + Displays a specific chapter in the rendition iframe. + + If no chapter URL is provided, it displays the first chapter in the + spine. It also handles embedding of assets like images. + + :param chapter_url: The URL of the chapter to display. Can include an + anchor. + :type chapter_url: Optional[str] + """ if not self.book.spine: return - anchor: Optional[str] = None chapter_href: str if chapter_url and '#' in chapter_url: @@ -126,11 +155,23 @@ def _embed_asset(self, element: ET.Element, attribute: str, chapter_path: str) - pass def next_chapter(self, event: Optional[Any] = None) -> None: + """ + Displays the next chapter in the book's spine. + + :param event: An optional event object (e.g., from a button click). + :type event: Optional[Any] + """ if self.current_chapter_index < len(self.book.spine) - 1: self.current_chapter_index += 1 self.display(self.book.spine[self.current_chapter_index]) def previous_chapter(self, event: Optional[Any] = None) -> None: + """ + Displays the previous chapter in the book's spine. + + :param event: An optional event object (e.g., from a button click). + :type event: Optional[Any] + """ if self.current_chapter_index > 0: self.current_chapter_index -= 1 self.display(self.book.spine[self.current_chapter_index])