EbookLib
A Python library for reading, writing, and manipulating EPUB2/EPUB3 ebook files programmatically.
Repository Health
Technical Analysis
EbookLib is a pure Python library for creating, reading, and modifying EPUB2 and EPUB3 ebook files. It exposes a straightforward object model — EpubBook, EpubHtml, EpubImage, EpubNav, EpubNcx — that maps directly onto the parts of an EPUB package: metadata, spine, table of contents, guide, and content items, so developers can assemble or inspect ebooks without hand-rolling zip and XML handling.
Actively developed since 2013, it’s used by dozens of downstream projects — Booktype, Audiblez, ebook2audiobook, Marker, DocsGPT — to convert other document formats into distributable EPUB files, or to extract text and images from EPUBs for audiobook generation, LLM ingestion, and document-conversion pipelines. Recent releases (0.20+) modernized the codebase with full type annotations and dropped Python 2 support in favor of Python 3.10+.
What You Get
- Full EpubBook object model covering metadata, spine, guide, and table of contents
- read_epub() / write_epub() for round-tripping existing EPUB files to and from disk
- EpubHtml, EpubImage, and EpubItem classes for building chapters, cover art, and other assets
- Automatic NCX and Nav (EPUB2/EPUB3 table-of-contents) document generation
- A plugin system (booktype, standard, tidyhtml, sourcecode) for post-processing content during writing
- A type-annotated public API with a py.typed marker for downstream static type checking
Common Use Cases
- Programmatically generating EPUB ebooks from HTML or converted Markdown content
- Extracting text and images from existing EPUB files for search indexing or LLM ingestion
- Converting other document formats into EPUB as part of a custom publishing pipeline
- Building audiobook-generation tools that walk an EPUB’s spine and table of contents
- Digital publishing platforms that need to inspect or repackage EPUB metadata
Under The Hood
Architecture
The codebase is organized as a modular, layered library rather than a single monolith: book.py holds the EpubBook state container, items.py defines the item type hierarchy (EpubItem, EpubHtml, EpubImage, EpubNav, EpubNcx, EpubCover), and reader.py / writer.py implement I/O against that shared model using lxml for XML and stdlib zipfile for the container. Supporting concerns — table-of-contents structures, constants/templates, and shared parsing helpers — live in toc.py, consts.py, and utils.py. The historic single-module epub.py is kept as a thin, fully-typed backwards-compatible facade re-exporting everything, so code written against older versions of the library still imports correctly after the internal split.
Tech Stack
Pure Python targeting 3.10+, with a single runtime dependency (lxml) for XML parsing and serialization and stdlib zipfile for the EPUB container format. The build uses a modern pyproject.toml (setuptools backend) with setup.py retained only for legacy tooling compatibility. Development tooling includes ruff for linting and formatting, ty for static type checking, and pytest for tests, all wired into a GitHub Actions matrix across Python 3.10 through 3.14.
Code Quality
A dedicated tests/ directory covers the book model, EPUB cover handling, HTML items, generic items, mtime/UTC handling, and utility functions. Every pull request runs ruff format --check, ruff check, a ty type-check pass, and the full pytest suite across five Python versions before merge. The public API carries full type hints and ships a py.typed marker, and a custom EpubException is used for domain errors rather than generic exceptions.
API Design
The public surface is deliberately small: a handful of classes that map one-to-one onto EPUB spec concepts (EpubBook, EpubHtml, EpubImage, EpubNav, EpubNcx) let a developer assemble a book — set metadata, add items, define spine and TOC, call write_epub() — with minimal boilerplate. Backwards compatibility is treated as a first-class concern: the epub.py facade preserves the original flat import style even though the implementation was split into focused modules, and reader/writer options (e.g. ignore_ncx) are exposed as simple dict overrides rather than a sprawling configuration surface.