coverage.renderer¶
SpaRenderer: emit the covapp SPA coverage report (Plan C).
The pivot renderer — this is what makes the built covapp bundle (Task 2)
THE coverage report. It copies the static bundle (index.html + dist/)
into the report directory and writes the JS data chunks (Task 1’s
spa_data.emit_chunks) that bundle consumes at file:// or any served
subpath (spec §2 — no server, no ES modules, no network fetches).
Mirrors the retired Jinja renderer’s missing-dist degrade
(_copy_static) without importing from it.
-
otto.coverage.renderer.spa_renderer.STATIC_DIR =
PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/otto-sh/checkouts/stable/src/otto/_webassets/covapp')¶ The built covapp bundle (
make web->vite build --config vite.covapp.config.ts).Not committed — a hostless unit-test checkout that skipped
make webhas noindex.html/dist/here;SpaRenderer._copy_bundledegrades gracefully rather than failing the whole report.
-
class otto.coverage.renderer.spa_renderer.SpaRenderer(output_dir: Path, project_name: str =
'Coverage Report', *, extra_markers: list[str] | None =None, prefix: Path | None =None)¶ Bases:
objectRender a
CoverageStoreto a covapp SPA report directory.- Parameters:¶
output_dir – Directory to write the report into (created if needed).
project_name – Title shown in the report (
IndexPayload.project_name).extra_markers – Extra source exclusion-marker strings (spec §8), forwarded from
[coverage.exclusions].markersvia the reporter. Scanned alongside the built-inLCOV_EXCL_*markers when annotating each file’s source (seespa_data.emit_chunks).prefix – Strip this leading directory from file paths shown in the report (display only, like
genhtml --prefix). Files outside the prefix display unchanged; chunk names always use the full canonical path, never the display path.
- render(store: CoverageStore) None¶
Render the full SPA report: copy the bundle, then emit the data chunks.
Emit the JS data chunks the coverage SPA (Plan C) consumes.
This is the pure-Python half of the SPA report: it turns a
CoverageStore into
cov_data/index.js— one classic-script assignment (window.__OTTO_COV__ = {...};) carrying the report-wideIndexPayload-shaped dict (config, run table, and a directory tree of rollupStats), andcov_data/files/<mangled>.js— one classic-script call (window.__OTTO_COV_FILE__({...});) per file, carrying its annotated source and per-line hit/branch/state data.
It deliberately mirrors the mechanics of the retired Jinja renderer (display-path prefix stripping, path mangling, tier labels/colors, the source-exclusion scan) without importing from it.
-
otto.coverage.renderer.spa_data.OTTO_COV_DATA_FORMAT : int =
1¶ IndexPayload["format"]/FileChunk["stamp"]-adjacent format marker.Bump alongside the TypeScript
EXPECTED_DATA_FORMATconstant, or never.
- otto.coverage.renderer.spa_data.make_stamp() str¶
Return a fresh report stamp: UTC timestamp + a short random suffix.
Written once per
emit_chunks()call and carried verbatim on the index payload and every file chunk, so the frontend can detect a stale/partial chunk cache against a freshly generated index.
- otto.coverage.renderer.spa_data.mangle_path(path: Path) str¶
Mangle a canonical file path into a filesystem/URL-safe chunk id.
Same scheme the retired Jinja renderer used: full canonical path (never the display path), so chunk filenames stay stable across
--prefixchanges.
- otto.coverage.renderer.spa_data.build_index_payload(store: CoverageStore, *, project_name: str, prefix: Path | None, stamp: str) dict[str, Any]¶
Build the
IndexPayloaddict written tocov_data/index.js.Reads whatever exclusion data is already on each
FileRecord— it does not scan source itself;emit_chunks()runs that scan (mirroring the retired Jinja renderer) and annotates the store before this function’s per-file stats are computed.
- otto.coverage.renderer.spa_data.emit_chunks(store: CoverageStore, output_dir: Path, *, project_name: str, prefix: Path | None, extra_markers: list[str] | None, stamp: str) None¶
Write
cov_data/index.jsand onecov_data/files/<mangled>.jsper file.Every file’s source-exclusion scan runs first (annotating
FileRecord.excluded_lineson the store), so the index payload’s per-nodeflags.excludedcounts reflect it — the reporter’s laterstore.save()then persists the same annotation, exactly like the retired Jinja renderer did.