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.
freeze
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
Summary of a freeze run.
One addressable section inside aSearchEntry.
Block-grained entries enable deep-linking search results to
#anchor targets rather than only page URLs. bodyshould be…
Structured search data captured at render time.
Route handlers callsearch_contribute() during freeze to register structured metadata for the current page. This bypasses…
Register a search contribution for the current freeze render.
No-op outside of freeze (the ContextVar defaults toNone).
Map a URL path to an output file path.
/docs/get-started/ → output_dir/docs/get-started/index.html
/ → output_dir/index.html
Replace\{name} or {name:type}placeholders with values.
Convert an absolute URL to a relative path toindex.html.
Both arguments are absolute paths (e.g./articles/foo). The result is relative from…
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…
Return the directory depth of a URL path (for relative path computation).
Extract the page title from
.
Extract a text snippet from the
Build a search index from rendered (url, html) pairs.
Each entry hasu (relative file path), t(title), and
optionallyd(text snippet for…
Build a structured search manifest from render-time contributions.
Pages that contributed structured data viasearch_contribute() get full metadata (category, tags, TOC, description). Pages…
Return the set of internal URLs referenced by<a href>in html.
Fragments (#section) and query strings (?x=1) are…
Build the cross-reference graph from rendered pages.
Manifest format::
{
"version": 1,
"pages": {
"/docs/intro/": {
"references": ["/docs/a/", "/docs/b/"],
"referenced_by": ["/docs/c/"]
}
}
}
…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…
Classify routes and expand parameterized ones.
Returns (urls, skipped_reasons, warnings).
Return(route_path, spec)for live blocks matching url.
An empty list means this URL has no live-block rewrites to apply.
Render the htmx placeholder that replaces a live block in frozen HTML.
Rewrite declared live blocks in html as htmx placeholders.
Matches urlto a registered route, then for each live block declared on that route…
Freeze the app to static HTML files.
Renders every freezable GET route through the full ASGI stack and writes the output to output_dir.
FreezeResult
class
Summary of a freeze run.
BlockEntry
class
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.
SearchEntry
class
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.
search_contribute
function
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 | Default | Description |
|---|---|---|---|
entry
|
SearchEntry
|
— |
_url_to_file_path
function
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 | Default | Description |
|---|---|---|---|
url
|
str
|
— | |
output_dir
|
Path
|
— |
_expand_params
function
def _expand_params(route_path: str, params: dict[str, str]) -> str
Replace\{name} or {name:type}placeholders with values.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
route_path
|
str
|
— | |
params
|
dict[str, str]
|
— |
_make_relative
function
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 | Default | Description |
|---|---|---|---|
from_url
|
str
|
— | |
to_url
|
str
|
— |
_relativize_html
function
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 | Default | Description |
|---|---|---|---|
html
|
str
|
— | |
page_url
|
str
|
— | |
known_urls
|
frozenset[str]
|
— |
_page_depth
function
def _page_depth(url: str) -> int
Return the directory depth of a URL path (for relative path computation).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
url
|
str
|
— |
_extract_title
function
def _extract_title(html: str) -> str
Extract the page title from
.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
html
|
str
|
— |
_extract_snippet
function
def _extract_snippet(html: str, max_len: int = 200) -> str
Extract a text snippet from the
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
html
|
str
|
— | |
max_len
|
int
|
200
|
_build_search_index
function
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 | Default | Description |
|---|---|---|---|
rendered
|
list[tuple[str, str]]
|
— |
_build_rich_search_index
function
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 | Default | Description |
|---|---|---|---|
contributions
|
list[SearchEntry]
|
— | |
rendered
|
list[tuple[str, str]]
|
— |
_extract_internal_hrefs
function
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 | Default | Description |
|---|---|---|---|
html
|
str
|
— | |
known_urls
|
frozenset[str]
|
— |
_build_xref_graph
function
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 | Default | Description |
|---|---|---|---|
rendered
|
list[tuple[str, str]]
|
— | |
known_urls
|
frozenset[str]
|
— |
_inject_static_search
function
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 | Default | Description |
|---|---|---|---|
html
|
str
|
— | |
depth
|
int
|
— | |
index_path
|
str
|
— |
_enumerate_urls
function
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 | Default | Description |
|---|---|---|---|
app
|
App
|
— |
_live_blocks_for_url
function
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 | Default | Description |
|---|---|---|---|
app
|
App
|
— | |
url
|
str
|
— |
_live_placeholder_html
function
def _live_placeholder_html(url: str, spec: LiveBlockSpec) -> str
Render the htmx placeholder that replaces a live block in frozen HTML.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
url
|
str
|
— | |
spec
|
LiveBlockSpec
|
— |
_apply_live_blocks
function
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 | Default | Description |
|---|---|---|---|
html
|
str
|
— | |
url
|
str
|
— | |
app
|
App
|
— | |
captures
|
list[tuple[str, dict[str, Any]]]
|
— | |
errors
|
list[str]
|
— |
freeze
function
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 | Default | Description |
|---|---|---|---|
app
|
App
|
— | |
output_dir
|
Path
|
— | |
exclude
|
list[str] | None
|
None
|
View source · /home/runner/work/chirp/chirp/site/../src/chirp/freeze.py:1