Repository navigation
feat: share process-global widgets across sessions and re-renders (#348) - #351
Merged
Merged
Conversation
cpsievert
marked this pull request as ready for review
October 27, 2026 22:24
cpsievert
marked this pull request as draft
October 27, 2026 22:39
cpsievert
marked this pull request as ready for review
October 27, 2026 23:04
cpsievert
force-pushed
the
feat-348-shared-widgets
branch
from
October 27, 2026 23:45
e53c07c to
8277f1f
Compare
Collaborator
Author
|
Heads-up: this PR was auto-marked as merged when its base branch |
This was referenced Oct 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this matters
Apps built on ipyvuetify or ipyvue (and anything that uses them under the hood, like ipyvolume's pylab API) hang for ~30 s after the first re-render or in a second user's session, and one dangling reference blanks every vuetify widget on the page. The cause: ipyvue and ipyvuetify create widgets for the whole Python process (
force_load_instance, one cachedTemplateper.vuefile,theme), but shinywidgets gives every widget to one session and closes it when that render is invalidated.With this PR those widgets render, re-render, and work across concurrent sessions, with no per-package workarounds. It also adds a public
shared_lifetime()for widgets you want every session to display.What changes for users
VueTemplates and module-leveltheme.dark = True, across re-renders and sessions (new Playwright regression test).shared_lifetime()(new, public): construct a widget inside it and every session shows the same Python widget. Any user's interaction changes it for everyone, and it is never freed, so it is for static content or deliberately shared state. The docstring says how to use it without unbounded growth.session_lifetime(), or shared with every user withshared_lifetime().Why it sits below #329
#329 currently works around this same gap for ipyvolume with
neutralize_ipyvolume_pylab()and an ipyvue/ipyvuetify import-tolerance entry. This PR replaces both, so #329 is restacked on this branch without them and the workarounds never reachmain.How it works (short)
Widgets known to be process-global (listed packages' import-time singletons, ipyvue's cached templates, and
shared_lifetime()widgets) get a comm that fans out to every session that uses them. They are opened in a session at session start, at render time, and when a referencing widget's comm opens, and they are skipped by render and session cleanup.Known limitations
box.children += (HTML(...),)on a shared box) is an unsupported shape. Other sessions see a dangling reference rather than an error.target/shadow) belong to that browser. Confirmed in a browser: a second session waits ~30 s for the missing model (Timeout waiting for widget model) and the affected outputs never render (two-session Playwright regression test intests/playwright/shared_pythreejs/). Give such traits explicit values built insideshared_lifetime(); the docstring says so. The new dangling-reference warning also fires in this scenario, naming the trait and the remedy.Updates from review
open_shared_in()warns when a shared widget references a session-owned or closed widget, and a guard inSharedShinyComm.send()scans outgoing state forIPY_MODEL_references: process-global references are opened in the missing sessions on the spot (this keeps the documented "lazy construction in a callback" pattern working), while session-owned/closed references produce aUserWarningnaming both widgets, the browser symptom, and theshared_lifetime()remedy. Also fixesclose_render_widgets()closing a surviving shared widget'sLayout/HTMLStyledefaults (surviving process-global widgets now root the keep-walk).tests/unit/test_upstream_internals.py): the ipyvue/ipyvuetify heuristics' assumptions (template_registry, import-time module bindings) are now asserted against the real packages, so an upstream restructure fails the unit suite immediately instead of surfacing as a Playwright timeout.session_lifetime()un-deprecated: it was accidentally grouped under# Soft deprecatedin__all__(swept in when appended in Add session_lifetime() and fix widget cleanup leaks #258; the comment was introduced forregister_widgetinrender_widgetnow attaches it's return value to the decorated function #119). It's now grouped withshared_lifetime()under# Lifetime methods.render_widgetrather thanrender_pythreejsso it runs on this branch's feat: let the browser open widget comms (bqplot toolbar, pythreejs light defaults) #346 base.Verification
make check: 484 unit tests passed on the restacked branch (the 9 original commits plus the 5 review-feedback commits).render_ipyvuetify(re-renders and concurrent sessions) andshared_pythreejs(default vs. explicit light target/shadow across two sessions).render_geoviews/render_lonboardcovered by CI.render_bqplot/render_ipydatagridlifecycle tests flake intermittently onmaintoo (verified on the base commit).