recon_gen.common.pdf.audit_chrome

Reportlab document template + page chrome helpers.

Generic reportlab plumbing extracted from cli/audit.py: a BaseDocTemplate subclass that handles bookmarks + TOC entries + Page X of N page-count threading via a multiBuild-aware closure, plus level-tagged Paragraph helpers and a themed footer factory.

Deliberately stays domain-agnostic: no audit-specific story builders or content live here. cli/audit.py (and any future PDF-generating artifact) imports these primitives and assembles its own story.

Functions

bookmarked_h1(text, styles)

Heading1 paragraph tagged for PDF outline + TOC at level 0.

bookmarked_h3(text, styles)

Heading3 paragraph tagged for PDF outline + TOC at level 1.

make_footer_drawer(theme, *, version, ...)

Build a per-page footer drawer with U.6 chrome.

Classes

BookmarkedDocTemplate(*args[, ...])

BaseDocTemplate proxy with bookmark + TOC + page-count support.

class recon_gen.common.pdf.audit_chrome.BookmarkedDocTemplate(*args, total_pages_holder=None, **kwargs)[source]

Bases: object

BaseDocTemplate proxy with bookmark + TOC + page-count support.

Defined as a thin proxy via __new__-style indirection so reportlab is only imported when the caller actually needs it (so the parent CLI loads cleanly without the PDF extra installed).

Builds the PDF outline (left-sidebar nav) + feeds the TableOfContents flowable’s notification stream from any flowable tagged with a _bookmark_level attribute (use bookmarked_h1 / bookmarked_h3). Also records the final page count after each multiBuild pass into the caller-provided total_pages_holder so the footer drawer can render “Page X of Y” without resorting to a NumberedCanvas (which breaks bookmark→page refs).

Parameters:
  • args (Any)

  • total_pages_holder (list[int] | None)

  • kwargs (Any)

Return type:

Any

recon_gen.common.pdf.audit_chrome.bookmarked_h1(text, styles)[source]

Heading1 paragraph tagged for PDF outline + TOC at level 0.

styles is a reportlab StyleSheet1; returns a reportlab Paragraph. Both annotated Any to avoid forcing the reportlab import at module load — the PDF extra is optional.

Used by every per-section heading the reader should be able to jump to from the bookmark sidebar or the TOC page.

Return type:

Any

Parameters:
  • text (str)

  • styles (Any)

recon_gen.common.pdf.audit_chrome.bookmarked_h3(text, styles)[source]

Heading3 paragraph tagged for PDF outline + TOC at level 1.

styles/return both Any for the same reason as bookmarked_h1.

Return type:

Any

Parameters:
  • text (str)

  • styles (Any)

Build a per-page footer drawer with U.6 chrome.

theme is a ThemePreset; typed Any to avoid pulling the theme module into the reportlab module’s import graph (the import happens inside the render function so this module loads without the PDF extra installed). Return is the inner page-template callable reportlab invokes per page with (canvas, doc).

“Page X of Y” needs the FINAL page count, which only stabilizes at the end of a multiBuild pass. We piggyback on the fact that multiBuild runs the build at least twice (once for TableOfContents to collect entries, once to render the resolved TOC): pass 1’s footer renders “Page X of ?” while total_pages_holder[0] == 0; BookmarkedDocTemplate overrides _allSatisfied to record self.page (now stable) into the holder; pass 2’s footer reads it back as “Page X of N”.

Tried the standard NumberedCanvas pattern (defer showPage, replay buffered state in save) — it broke every PDF bookmark, because dict(self.__dict__) snapshots include _destinations / page-ref state, and restoring an earlier snapshot at save time overwrote the accumulated bookmark→page refs with the LAST state’s, collapsing every outline entry to page 1. The two-pass closure here keeps reportlab’s normal page-template chrome flow untouched, so bookmarks resolve correctly through the standard machinery.

Per U.7: when provenance is computed, the footer renders the real short fingerprint (first 8 hex of composite SHA256); when not, the pending placeholder.

Return type:

Callable[[Any, Any], None]

Parameters:
  • theme (Any)

  • version (str)

  • generated_at (datetime)

  • total_pages_holder (list[int])

  • provenance (ProvenanceFingerprint | None)