Module

freeze

Freeze — render routes to static HTML files.

Walks the app's route table after freeze, renders each freezable URL through the full ASGI middleware stack via TestClient, and writes the output to disk.

URLs in the frozen HTML are rewritten from absolute (/about) to relative (../about/) so the output works on any static host — S3, GitHub Pages, Cloudflare, or plainfile://— without a server to resolve clean URLs.

Classes

FreezeResult 5
Summary of a freeze run.

Summary of a freeze run.

Attributes

Name Type Description
pages_written int
pages_skipped int
errors list[str]
urls tuple[str, ...]
elapsed float
BlockEntry 5
One addressable section inside a ``SearchEntry``. Block-grained entries enable deep-linking search…

One addressable section inside aSearchEntry.

Block-grained entries enable deep-linking search results to #anchor targets rather than only page URLs. bodyshould be plain text (tags stripped) for direct match scoring.

Attributes

Name Type Description
block_id str
heading str
body str
anchor str
depth int
SearchEntry 9
Structured search data captured at render time. Route handlers call `search_contribute`() during f…

Structured search data captured at render time.

Route handlers callsearch_contribute() during freeze to register structured metadata for the current page. This bypasses HTML scraping entirely — category, tags, TOC, and description survive from the template context to the search index.

Attributes

Name Type Description
url str
title str
description str
category str
tags frozenset[str]
toc tuple[dict[str, Any], ...]
template_name str
body str
blocks tuple[BlockEntry, ...]

Functions

search_contribute 1 None
Register a search contribution for the current freeze render. No-op outside of…
def search_contribute(entry: SearchEntry) -> None

Register a search contribution for the current freeze render.

No-op outside of freeze (the ContextVar defaults toNone).

Parameters
Name Type Description
entry SearchEntry
_url_to_file_path 2 Path
Map a URL path to an output file path. ``/docs/get-started/`` → ``output_dir/d…
def _url_to_file_path(url: str, output_dir: Path) -> Path

Map a URL path to an output file path.

/docs/get-started/output_dir/docs/get-started/index.html /output_dir/index.html

Parameters
Name Type Description
url str
output_dir Path
Returns
Path
_expand_params 2 str
Replace ``{name}`` or ``{name:type}`` placeholders with values.
def _expand_params(route_path: str, params: dict[str, str]) -> str
Parameters
Name Type Description
route_path str
params dict[str, str]
Returns
str
_make_relative 2 str
Convert an absolute URL to a relative path to ``index.html``. Both arguments a…
def _make_relative(from_url: str, to_url: str) -> str

Convert an absolute URL to a relative path toindex.html.

Both arguments are absolute paths (e.g./articles/foo). The result is relative from the directory containing from_url/index.html and points to to_url/index.html so thatfile://browsing works (no server-side index resolution needed).

Examples::

_make_relative("/articles/foo", "/about")
    # "../../about/index.html"
_make_relative("/articles/foo", "/")
    # "../../index.html"
_make_relative("/", "/about")
    # "about/index.html"
Parameters
Name Type Description
from_url str
to_url str
Returns
str
_relativize_html 3 str
Rewrite absolute URL paths in *html* to relative paths. Only rewrites paths th…
def _relativize_html(html: str, page_url: str, known_urls: frozenset[str]) -> str

Rewrite absolute URL paths in html to relative paths.

Only rewrites paths that match known_urls (the set of frozen pages). External URLs, anchors, and unknown paths are left untouched.

Parameters
Name Type Description
html str
page_url str
known_urls frozenset[str]
Returns
str
_page_depth 1 int
Return the directory depth of a URL path (for relative path computation).
def _page_depth(url: str) -> int
Parameters
Name Type Description
url str
Returns
int
_extract_title 1 str
Extract the page title from or first .
def _extract_title(html: str) -> str
Parameters
Name Type Description
html str
Returns
str
_extract_snippet 2 str
Extract a text snippet from the element for search matching.
def _extract_snippet(html: str, max_len: int = 200) -> str
Parameters
Name Type Description
html str
max_len int Default:200
Returns
str
_build_search_index 1 list[dict[str, str]]
Build a search index from rendered (url, html) pairs. Each entry has ``u`` (re…
def _build_search_index(rendered: list[tuple[str, str]]) -> list[dict[str, str]]

Build a search index from rendered (url, html) pairs.

Each entry hasu (relative file path), t(title), and optionallyd(text snippet for full-text matching).

Parameters
Name Type Description
rendered list[tuple[str, str]]
Returns
list[dict[str, str]]
_build_rich_search_index 2 dict[str, Any]
Build a structured search manifest from render-time contributions. Pages that …
def _build_rich_search_index(contributions: list[SearchEntry], rendered: list[tuple[str, str]]) -> dict[str, Any]

Build a structured search manifest from render-time contributions.

Pages that contributed structured data viasearch_contribute() get full metadata (category, tags, TOC, description). Pages without contributions fall back to HTML scraping for title + snippet.

The manifest format (v2)::

{
    "version": 2,
    "facets": {"category": [...], "tags": [...]},
    "entries": [{"u", "t", "d", "c", "tags", "toc", "body", "blocks"}, ...]
}

Each block entry has{"id", "h", "b", "a", "d"}for block id, heading, plain-text body, anchor (href fragment), and heading depth.

Version 2 is a superset of v1: readers that ignoreblocksbehave identically to v1 readers.

Parameters
Name Type Description
contributions list[SearchEntry]
rendered list[tuple[str, str]]
Returns
dict[str, Any]
_extract_internal_hrefs 2 list[str]
Return the set of internal URLs referenced by ```` in *html*. Fragments (``#se…
def _extract_internal_hrefs(html: str, known_urls: frozenset[str]) -> list[str]

Return the set of internal URLs referenced by<a href>in html.

Fragments (#section) and query strings (?x=1) are stripped before matching against known_urls. External links (https:, mailto:) are not captured because the regex anchors on href="/.

Parameters
Name Type Description
html str
known_urls frozenset[str]
Returns
list[str]
_build_xref_graph 2 dict[str, Any]
Build the cross-reference graph from rendered pages. Manifest format:: { …
def _build_xref_graph(rendered: list[tuple[str, str]], known_urls: frozenset[str]) -> dict[str, Any]

Build the cross-reference graph from rendered pages.

Manifest format::

{
    "version": 1,
    "pages": {
        "/docs/intro/": {
            "references": ["/docs/a/", "/docs/b/"],
            "referenced_by": ["/docs/c/"]
        }
    }
}

Lists are sorted alphabetically so the output is deterministic. Self- references are excluded.

Parameters
Name Type Description
rendered list[tuple[str, str]]
known_urls frozenset[str]
Returns
dict[str, Any]
_inject_static_search 3 str
Inject the client-side search script into a frozen HTML page. Only injects if …
def _inject_static_search(html: str, depth: int, index_path: str) -> str

Inject the client-side search script into a frozen HTML page.

Only injects if the page contains a.chirp-docs-searchinput. Uses a<script src> for the index (works on file://) and an inline script for the search logic.

Parameters
Name Type Description
html str
depth int
index_path str
Returns
str
_enumerate_urls 1 tuple[list[str], list[st…
Classify routes and expand parameterized ones. Returns (urls, skipped_reasons,…
def _enumerate_urls(app: App) -> tuple[list[str], list[str], list[str]]

Classify routes and expand parameterized ones.

Returns (urls, skipped_reasons, warnings).

Parameters
Name Type Description
app App
Returns
tuple[list[str], list[str], list[str]]
_live_blocks_for_url 2 list[tuple[str, LiveBloc…
Return ``(route_path, spec)`` for live blocks matching *url*. An empty list me…
def _live_blocks_for_url(app: App, url: str) -> list[tuple[str, LiveBlockSpec]]

Return(route_path, spec)for live blocks matching url.

An empty list means this URL has no live-block rewrites to apply.

Parameters
Name Type Description
app App
url str
Returns
list[tuple[str, LiveBlockSpec]]
_live_placeholder_html 2 str
Render the htmx placeholder that replaces a live block in frozen HTML.
def _live_placeholder_html(url: str, spec: LiveBlockSpec) -> str
Parameters
Name Type Description
url str
spec LiveBlockSpec
Returns
str
_apply_live_blocks 5 str
Rewrite declared live blocks in *html* as htmx placeholders. Matches *url* to …
def _apply_live_blocks(html: str, url: str, app: App, captures: list[tuple[str, dict[str, Any]]], errors: list[str]) -> str

Rewrite declared live blocks in html as htmx placeholders.

Matches url to a registered route, then for each live block declared on that route renders it in isolation with the captured template context and replaces the exact string match in html. No-op when nothing matches.

Parameters
Name Type Description
html str
url str
app App
captures list[tuple[str, dict[str, Any]]]
errors list[str]
Returns
str
freeze 3 FreezeResult
Freeze the app to static HTML files. Renders every freezable GET route through…
async
async def freeze(app: App, output_dir: Path, *, exclude: list[str] | None = None) -> FreezeResult

Freeze the app to static HTML files.

Renders every freezable GET route through the full ASGI stack and writes the output to output_dir.

Parameters
Name Type Description
app App
output_dir Path
exclude list[str] | None Default:None
Returns
FreezeResult