Skip to content

Fix Layout hooks crash and stuck placeholder#810

Merged
SimonHeybrock merged 5 commits intomainfrom
worktree-805-layout-hooks
Mar 19, 2026
Merged

Fix Layout hooks crash and stuck placeholder#810
SimonHeybrock merged 5 commits intomainfrom
worktree-805-layout-hooks

Conversation

@SimonHeybrock
Copy link
Member

@SimonHeybrock SimonHeybrock commented Mar 17, 2026

Summary

Two fixes for cells getting permanently stuck as placeholders when a workflow produces hv.Layout plots:

  • has_layout guard (_get_session_composed_plot): Additionally check dmap.type is hv.Layout — the DynamicMap's resolved type after Bokeh renders it. The existing plotter.get_cached_state() check can miss a Layout during a background plotter replacement (thread race between two reads of state.plotter within the same function). The dmap.type check is race-free because it inspects the object that hooks will be applied to.
  • Version bump ordering (_poll_for_plot_updates): Defer last_seen_version bump until after the cell rebuild succeeds. Previously the version was marked "seen" before the rebuild, so any failure (not just the Layout error) left the cell stuck permanently.

Testability note

The (a) race requires thread interleaving between two property reads in the same synchronous function — not reproducible deterministically in a single-threaded test. The fix is a code-review-level improvement (strictly better guard). Only (b) has a deterministic regression test.

Test plan

  • test_poll_creates_session_layer_for_layout_plotter — Layout plotter poll happy path
  • test_failed_rebuild_does_not_bump_version — confirms (b) regression caught by reverting the fix

Fixes #805

🤖 Generated with Claude Code

Tests for both sub-issues:

(a) has_layout guard misses Layout when plotter's cached state is
    transiently None, causing ValueError when hooks are applied to
    an already-evaluated Layout-type DynamicMap.

(b) last_seen_version is bumped before the rebuild, so a failed
    rebuild is never retried — the cell stays as a placeholder.
(a) Check `dmap.type is hv.Layout` in addition to
    `plotter.get_cached_state()`. Once Bokeh has evaluated a
    DynamicMap, its `.type` is set; `.opts(hooks=...)` rejects
    Layout-typed DynamicMaps.  The plotter's cached state can be
    transiently unavailable during a background plotter replacement,
    making the old guard miss the Layout.

(b) Defer `last_seen_version` bump until after the cell rebuild
    succeeds.  Previously the version was marked as "seen" before
    the rebuild, so a failed rebuild was never retried and the cell
    stayed as a placeholder permanently.

Fixes #805
Replace isolated mechanism-proof tests with three integration tests
that exercise the actual poll+rebuild code path:

- Layout plotter creates session layer with components
- Rebuild succeeds after Bokeh evaluates DynamicMap as Layout
- Failed rebuild leaves version stale for retry
The (a) race requires thread interleaving between two property reads
in the same synchronous function — not reproducible deterministically.
Keep only the happy-path Layout poll test and the (b) version-bump test.
@github-project-automation github-project-automation bot moved this to In progress in Development Board Mar 17, 2026
@SimonHeybrock SimonHeybrock moved this from In progress to Selected in Development Board Mar 17, 2026
@SimonHeybrock SimonHeybrock marked this pull request as ready for review March 17, 2026 07:51
@SimonHeybrock SimonHeybrock changed the title Fix Layout hooks crash and stuck placeholder (#805) Fix Layout hooks crash and stuck placeholder Mar 17, 2026
@nvaytet nvaytet self-assigned this Mar 18, 2026
@SimonHeybrock SimonHeybrock merged commit 19e6b3f into main Mar 19, 2026
4 checks passed
@SimonHeybrock SimonHeybrock deleted the worktree-805-layout-hooks branch March 19, 2026 05:31
@github-project-automation github-project-automation bot moved this from Selected to Done in Development Board Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Plot stuck on placeholder when DynamicMap resolves to Layout with hooks

2 participants