an.bench.capture#
Render one corpus fixture into a throwaway copy, and hand back its artifacts.
Two things this module exists to get right, both of which produce plausible numbers when got wrong:
Render into a copy. The render path mutates the project directory — scene
mtimes, the decisions log, .an/render_work — so rendering in place makes
the git sha in the ledger filename a lie about the tree that produced the row.
Do not inherit a stale render. shutil.copytree of a developer’s
checkout would carry .an/render_work and output/ across, frames/ is
never cleared, and ffmpeg’s image2 demuxer reads the contiguous
frame_%06d.png run from 0 — so a longer previous render is silently
appended to this one. Every encode-side metric pairs source frame i with
decoded frame i, so that appends garbage to one leg and shifts nothing on the
other. artifacts/ is deliberately kept except for one subdirectory: it
holds the audio cache, whose warm/cold state is recorded rather than destroyed
— but artifacts/shots is mall["shots"], the previous render’s per-shot
mp4s, and this module’s whole promise is that nothing of a previous render
crosses. It is gitignored, so it does not reproduce on a clean checkout: a
per-developer landmine, in the module whose docstring says the opposite.
Functions
|
Render |
|
Remove a capture's throwaway tree. |
|
|
|
Every distinct |
|
The renderer's own frame-count expression, reused rather than restated. |
Classes
|
One fixture's whole render. |
|
One rendered shot's artifacts. |
Exceptions
|
Bases:
RuntimeErrorgit statusdid not answer, so “the tree is clean” is not known.Separated from an empty result on purpose.
git statusfailing prints nothing to stdout, socheck=Falseturned every failure into “no dirty paths” — indistinguishable from a clean tree, and silently so. Measured: a concurrentgitin a linked worktree of this repo takesindex.lock,git statusexits nonzero with empty stdout, andtest_a_capture_leaves_the_repository_untouchedfails with[] != [...]— an assertion about the capture, pointing at nothing, in a run that has been green fifty times. A check that could not run is not evidence that nothing is wrong.
- class an.bench.capture.SceneCapture(name, source, prepared, project_dir, mp4, shots, resolution, fps, duration, n_declared_entity_refs, visual_kinds, asset_resolution, audio_cache, wall_seconds, determinism=<factory>, capture='', film=None)[source]#
Bases:
objectOne fixture’s whole render.
- capture: str#
How the frames left the browser (
"screenshot"/"canvas"), resolved the way the render resolves it. The decoded pixels are the same either way, so no metric moves — butwall_secondsdoes, several-fold, and a timing row is only readable beside the path that produced it (an#192 flipped the default).
- film: ShotCapture | None#
An ASSEMBLED scene’s composed frames (transitions, a sound layer —
an.assemble), as one segment: what the delivered mp4 shows.Nonefor a scene that is the concatenation of its shots, which is every scene before an#279’s core corpus. When set, every metric, the golden frames and the frame count read IT — pairing the shots’ frames against a film whose dissolves overlap them would measure the overlap, not the encoder.
- property frame_segments: list[ShotCapture]#
The frame sequence(s) the delivered mp4 shows, in order.
- class an.bench.capture.ShotCapture(shot_id, frames_dir, scene_json, runtime_dir, frame_count, duration=0.0, frame_sizes=())[source]#
Bases:
objectOne rendered shot’s artifacts.
- an.bench.capture.capture_fixture(name, fixture, *, repo_root, keep_render=None)[source]#
Render
fixturein a throwaway copy and return its artifacts.The copy lives until the caller is done with it — the metrics read the frames — so this is a context-free function that leaves the tree in place and hands back the path.
captured()is the scoped form.- Return type:
- an.bench.capture.dirty_paths(repo_root)[source]#
git status --porcelainlines, so a capture can prove it touched nothing.Raises
GitStatusUnavailablewhen git does not answer, rather than reporting a clean tree it never observed.
- an.bench.capture.distinct_png_sizes(frames_dir)[source]#
Every distinct
(width, height)among a shot’s frame PNGs, sorted.Read from each file’s IHDR — 24 bytes per frame — so reading all of them costs nothing and catches what sampling one would miss: a sequence whose size changes partway through, which is what a half-applied supersample produces.
Recorded here, enforced elsewhere. Rendering a fixture at a size the scene does not declare is a legitimate thing to do —
misc/bench/wave3_ab.pypatchesruntime.jstoresolution: k, autoDensity: falseand drivescapture_fixture()directly to measure the supersample — so this module reports what it saw andan.bench.runis where the bench’s invariant is asserted.
- an.bench.capture.expected_frame_count(duration, fps)[source]#
The renderer’s own frame-count expression, reused rather than restated.
max(1, int(round(duration * fps)))— and Python 3’sroundis banker’s rounding, somath.ceilorint(x + 0.5)silently disagrees on every half-frame duration.- Return type:
>>> expected_frame_count(2.5, 24) 60 >>> expected_frame_count(0.0, 24) 1