From a49437ee1edda562989a840b5817cc7ade30846f Mon Sep 17 00:00:00 2001 From: Aditya Vaidya Date: Fri, 16 Oct 2026 20:37:12 -0700 Subject: [PATCH 1/2] TST type-annotate the MP4 render test and its helpers Annotate test_rendering_downloads_an_mp4 and the helpers it uses: _render_setup, _mp4_boxes, _find_box, _play_mp4, _js_value and _js_attrs. A recursive _Box alias describes the MP4 box tree. _find_box now asserts that the box it returns holds data rather than child boxes, and the test asserts that fps is a number, so the rest type-checks under mypy. --- cortex/tests/test_webgl_headless.py | 36 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cortex/tests/test_webgl_headless.py b/cortex/tests/test_webgl_headless.py index 7adba20d0..dbd7199a5 100644 --- a/cortex/tests/test_webgl_headless.py +++ b/cortex/tests/test_webgl_headless.py @@ -13,7 +13,8 @@ import time import urllib.request import zipfile -from typing import Any +from pathlib import Path +from typing import Any, Optional, Union import numpy as np import pytest @@ -1184,7 +1185,7 @@ def _bump(surf, seed, sigma): # --------------------------------------------------------------------------- -def _js_attrs(handle, path): +def _js_attrs(handle: JSProxy, path: str) -> dict[str, JSON]: """Read a javascript object's properties, with values for the scalar ones. ``send(method="get", ...)`` cannot be used for this: for a non-object @@ -1221,11 +1222,11 @@ def _js_query( f"{path} went unanswered for {timeout} s" -def _js_value(handle, path): +def _js_value(handle: JSProxy, path: str) -> JSON: """Read one scalar javascript property, e.g. viewer.camera.fov.""" parent, _, name = path.rpartition(".") entry = _js_attrs(handle, parent)[name] - assert len(entry) > 1, f"{path} is not a scalar: {entry}" + assert isinstance(entry, list) and len(entry) > 1, f"{path} is not a scalar: {entry}" return entry[1] @@ -2287,7 +2288,9 @@ def test_rendering_an_animation_reproduces_the_quickflat_png(tmp_path): # --------------------------------------------------------------------------- -def _render_setup(handle, last=2, size=(320, 240)): +def _render_setup( + handle: JSProxy, last: int = 2, size: tuple[int, int] = (320, 240) +) -> None: """An animation of `last` + 1 frames, turning the brain, at a small size.""" handle.send(method="run", params=[ "window.viewer.ui._desc.camera._desc.create animation.action", []]) @@ -2309,11 +2312,17 @@ def _panel_status(handle): return _js_run(handle, "window.viewer._animPanel._statusText", []) -def _mp4_boxes(data, start=0, end=None): +# An MP4 box as (type, payload); a container box's payload is its child boxes. +_Box = tuple[bytes, Union[bytes, list["_Box"]]] + + +def _mp4_boxes( + data: bytes, start: int = 0, end: Optional[int] = None +) -> list[_Box]: """The box tree of an MP4, as a list of (type, payload) with containers expanded.""" containers = {b"moov", b"trak", b"mdia", b"minf", b"stbl", b"dinf"} end = len(data) if end is None else end - boxes = [] + boxes: list[_Box] = [] while start < end: size, kind = struct.unpack(">I4s", data[start:start + 8]) assert size >= 8, "bad box size %d at %d" % (size, start) @@ -2327,10 +2336,14 @@ def _mp4_boxes(data, start=0, end=None): return boxes -def _find_box(boxes, *path): +def _find_box(boxes: list[_Box], *path: bytes) -> bytes: for kind, payload in boxes: if kind == path[0]: - return payload if len(path) == 1 else _find_box(payload, *path[1:]) + if len(path) == 1: + assert isinstance(payload, bytes), f"{kind!r} is a container box" + return payload + assert isinstance(payload, list), f"{kind!r} is not a container box" + return _find_box(payload, *path[1:]) raise KeyError(b"/".join(path)) @@ -2355,7 +2368,7 @@ def _find_box(boxes, *path): """ -def _play_mp4(path): +def _play_mp4(path: str) -> dict[str, Any]: """Load an MP4 into a