Skip to content

PDF pipeline and API

This PDF pipeline page is for contributors changing prodockit.pdf or calling its Python API directly. Document authors should use Generate a PDF.

Follow the pipeline

flowchart TB
    subgraph row1[" "]
        direction LR
        config[zensical.toml and nav] --> render[Render each Markdown page]
        render --> fixup[Normalise page HTML]
        fixup --> assemble[Assemble document]
    end

    subgraph row2[" "]
        direction LR
        pandoc[Pandoc and Lua filter] --> weasy[WeasyPrint layout]
        weasy --> index[Optional index extraction]
        index --> final[Final PDF]
    end

    row1 -->|continues| row2

    style row1 fill:none,stroke:none
    style row2 fill:none,stroke:none

The configuration wrapper reads Zensical settings, renders each navigation page through Zensical, constructs Page objects, pre-renders diagrams and maths, and calls the lower-level builder. A generated index adds a second layout pass after term pages are known.

Use the public Python surface

API Purpose
build_pdf_from_zensical_config() High-level build using navigation and settings from zensical.toml
build_pdf() Lower-level build from prepared Page objects
Page One rendered source page plus its path, appendix, index, and running-header metadata
PdfBuildError Build failure carrying the underlying command output
build_source_bundle_from_zensical_config() High-level Markdown/configuration source-bundle build

Prefer build_pdf_from_zensical_config() when a caller already has a Zensical project. Use build_pdf() only when the caller owns page rendering and can supply complete HTML and metadata.

from prodockit.pdf.config import build_pdf_from_zensical_config

output = build_pdf_from_zensical_config("zensical.toml")
print(output)

The CLI wraps these functions with progress reporting, captured diagnostics, and non-zero exit status; the functions return paths or raise exceptions.

Know the internal modules

Module Responsibility
prodockit.pdf.config Zensical configuration, navigation flattening, page rendering, and high-level entry points
prodockit.pdf.build Pipeline orchestration and external-command execution
prodockit.pdf.html Page fix-ups, front matter, web/PDF-only content, and heading structure
prodockit.pdf.lua Pandoc Lua filter generation
prodockit.pdf.css Page size, margins, running headers/footers, duplex layout, and shared presentation
prodockit.pdf.icons Icon discovery and SVG resolution
prodockit.pdf.mermaid Mermaid CLI invocation and diagram assets
prodockit.pdf.source_bundle Markdown/configuration source PDF
prodockit.pdf.index Marker extraction, term-page mapping, and generated index
prodockit.pdf.release Host release lookup for cover markers

Keep transformation stages narrow. A change to HTML normalisation, CSS, the Lua filter, or an external tool can affect every page, so verify the complete PDF and built-output tests rather than relying on a unit test of the changed module alone.

Preserve source-bundle boundaries

The prodockit source-bundle command includes Markdown below docs_dir plus zensical.toml. It is intentionally separate from the rendered-document pipeline: it discovers files with git, writes a self-contained HTML document, and calls WeasyPrint without Pandoc. The lower-level source-bundle API can discover every non-ignored text file for a specialised caller, but that is not the command-line default.

Copyright text can contain links and line breaks, so it cannot be flattened into a CSS string. The PDF pipeline writes it as an HTML element and places it in the repeated footer with CSS Paged Media's position: running() and content: element(). Check the finished PDF when changing this path; intermediate HTML alone does not prove that links or line breaks survived.

Preserve actionable errors

PdfBuildError reports which external command failed and retains its captured output. Configuration wrappers also guard Zensical result-shape changes with a message naming the installed version and affected page. Do not replace these with an unlabelled subprocess status or raw KeyError; callers need to know which boundary changed.