Source code for annie.pages.lazy
"""Deferred UI work that survives a body refresh (UI helper).
The Browse/Annotator rows decode frames lazily. Doing that with a per-row
``ui.timer`` is fragile: NiceGUI's ``Timer._run_once`` enters its parent slot
*before* it checks for cancellation, so a one-shot timer whose row was refreshed
away raises ``RuntimeError: The parent slot ... has been deleted`` — flooding the
log.
So at **runtime** (event loop running) we defer with a tracked background task,
which has no parent slot to delete; the coroutine itself guards every UI mutation.
Only at **build time** (auto-index, no loop yet) do we fall back to a one-shot
timer parented to a persistent host, which is safe because nothing is being
refreshed during the initial build.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from nicegui import background_tasks, core, ui
if TYPE_CHECKING:
from collections.abc import Callable, Coroutine
from typing import Any
[docs]
def schedule(host: ui.element, factory: Callable[[], Coroutine[Any, Any, None]]) -> None:
"""Run ``factory()`` soon, surviving a refresh of the calling row.
Args:
host: A persistent element used only for the build-time timer fallback.
factory: A zero-arg coroutine function producing the deferred work.
"""
if core.loop is None: # build time: no running loop yet
with host:
ui.timer(0.05, factory, once=True)
else:
# Runtime: a tracked task (no parent slot to be deleted) that runs in the scheduling
# page's client context, so a refresh inside it redraws that page only.
background_tasks.create(factory(), name="annie-lazy", context=host.client)