Skip to main content

epub-blocks

epub-blocks is a dependency-free Python library for reproducibly extracting ordered, structured text blocks from EPUB 2 and EPUB 3 files. A declarative recipe selects an edition’s XHTML, assigns block types, and generates stable identifiers without edition-specific Python code or a pre-existing output table.

It requires Python 3.13 or later. The project is pre-1.0, so its public API and recipe format may still make breaking changes.

Installation

python -m pip install epub-blocks

The runtime package has no third-party dependencies.

What it does

The package:

  • safely reads EPUB package metadata and XHTML spine documents;
  • selects source documents and blocks with case-insensitive globs;
  • normalizes extracted text and omits configured EPUB semantic elements;
  • derives groups from source paths, heading markers, or explicit transitions;
  • generates flat and nested identifiers with per-group counters;
  • assigns output types through ordered source-block rules;
  • handles joins, splits, omissions, skipped blocks, and inserted material;
  • pins both the EPUB and the compiled extraction plan with SHA-256; and
  • writes headerless id, type, text TSV records.

A recipe is sufficient to generate a new base text. It does not need a separately stored list of expected identifiers or types. Existing outputs may be useful as test oracles while authoring a recipe, but they are not recipe inputs and are not read by epub-blocks.

The package does not compare editions, select preferred readings, or apply editorial corrections. Recipes describe source structure, not expected prose.

Inspecting an EPUB

Use the lower-level API to discover source blocks before writing a recipe:

from epub_blocks import extract_blocks

for block in extract_blocks(
    "book.epub",
    include_documents=["*chapter*.xhtml"],
    exclude_classes=["image-caption"],
):
    print(block.source_locator, block.tag, sorted(block.classes), block.text)

A locator such as s008:text/chapter-01.xhtml#1.3.2 combines the one-based spine position, EPUB-internal document path, and element path within the XHTML body. Recipes use the EPUB-local portion: text/chapter-01.xhtml#1.3.2.

Recipe example

Recipe version 1 remains the serialized format in epub-blocks 0.3.0:

{
  "recipe_version": "1",
  "metadata": {"name": "Example edition"},
  "epub": {
    "identifier": "9780000000000",
    "sha256": "f4f9c2d902a41b80732b2dce7ad01a57f615859c21417a5019e3cd8e4d271282"
  },
  "normalization": {
    "collapse_whitespace": true,
    "strip": true,
    "unicode_normalization": "NFC"
  },
  "omit_epub_types": ["noteref", "pagebreak"],
  "source_blocks": {
    "include_documents": ["text/chapter-*.xhtml"],
    "exclude_classes": ["image-caption"]
  },
  "output": {
    "groups": {
      "source_marker": {
        "pattern": "^CHAPTER\\s+([IVXLCDM]+)\\b",
        "case_insensitive": true
      },
      "capture_kind": "roman",
      "capture_width": 2
    },
    "identifiers": {
      "block": {
        "template": "{group}.{number:03d}",
        "start": 1
      },
      "line": {
        "template": "{group}.{block:03d}.{number:02d}",
        "start": 1
      }
    },
    "default": {"type": "paragraph", "role": "block"},
    "rules": [
      {
        "match": {"tag": "h1"},
        "type": "heading",
        "role": "fixed",
        "id": "{group}.000",
        "remove_prefix": {
          "pattern": "^CHAPTER\\s+[IVXLCDM]+\\s+",
          "case_insensitive": true
        }
      },
      {
        "match": {"classes": ["verse-first"]},
        "type": "line",
        "role": "line-start"
      },
      {
        "match": {"classes": ["verse"]},
        "type": "line",
        "role": "line"
      }
    ],
    "skip_source": [],
    "replacements": [],
    "insertions": [],
    "compiled_sha256": "28354978484f35525c616d138bdeb8f801039d665235ac88bd02f1a25791c410"
  }
}

This recipe generates identifiers such as 01.000, 01.001, 01.002.01, and 01.002.02. Rules are matched against source structure; no expected text or identifier table is consulted.

See the complete recipe specification and packaged JSON Schema.

Command line

epub-blocks book.epub recipe.json records.tsv

The output is headerless TSV with id, type, and extracted text columns. Standard CSV quoting with a tab delimiter preserves tabs and line breaks.

Python API

from epub_blocks import extract_recipe_file

records = extract_recipe_file("book.epub", "recipe.json")
for record in records:
    print(record.block_id, record.block_type, record.text)

compile_recipe_file returns the immutable in-memory extraction plan. Fragment and extract_fragments provide lower-level access to selected XHTML subtrees. The supported import surface is the names exported by epub_blocks.

Safety

EPUB files are untrusted ZIP and XML input. Default APIs bound archive size, individual and cumulative reads, compression ratios, XML size, element count, and nesting depth. Duplicate or unsafe paths and encrypted members are rejected. External DTDs are never loaded; internal subsets, entity declarations, other doctypes, and unknown named character references are rejected.

Recipes are trusted local configuration because they contain regular expressions. epub-blocks never executes EPUB scripts or fetches resources from the network.

Development

uv sync
uv run ruff format --check .
uv run ruff check .
uv run pyright
uv run coverage erase
uv run coverage run -m unittest discover -s tests
uv run coverage report
uv run python -m build
uv run twine check dist/*
uv run pyright --verifytypes epub_blocks --ignoreexternal

Coverage includes branches and enforces a 90% minimum. Tests build synthetic EPUBs; no EPUB files are committed. See CONTRIBUTING.md and CHANGELOG.md.

License

epub-blocks is available under the MIT License.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

epub_blocks-0.3.0.tar.gz (55.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

epub_blocks-0.3.0-py3-none-any.whl (35.9 kB view details)

Uploaded Python 3

File details

Details for the file epub_blocks-0.3.0.tar.gz.

File metadata

  • Download URL: epub_blocks-0.3.0.tar.gz
  • Upload date:
  • Size: 55.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for epub_blocks-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2591718d261fd5e4365825b3f176a40ef9b9e1ede8a3879877d2a4f64aee36cd
MD5 2a0cf43c89cf9b570d8f130be70c7806
BLAKE2b-256 b2d1512dcd32b61c8a5d79c8dd3f223ff50a03134cc6cafe4ee66813c9167472

See more details on using hashes here.

Provenance

The following attestation bundles were made for epub_blocks-0.3.0.tar.gz:

Publisher: release.yml on jtauber/epub-blocks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file epub_blocks-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: epub_blocks-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 35.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for epub_blocks-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 15cb357622886a61e039c557051212e1f9ddaf795c8503094c3ac0d921175a9b
MD5 38dc716f8998a1290267937109a2c57f
BLAKE2b-256 c22d4ec41d5a5c162d00054e1bb77126a087907f6ac678d5fe833242c9f018a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for epub_blocks-0.3.0-py3-none-any.whl:

Publisher: release.yml on jtauber/epub-blocks

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.0

2 files

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page