Skip to content

Title: st.progress() / other widgets raise AttributeError: 'NoneType' object has no attribute 'get_name' when called from a Python callback invoked by JS, even after add_script_run_ctx #2113

Description

@christykanto

When a Python callback is invoked asynchronously from JS (e.g. via pyodide.ffi.create_proxy, the pattern used to receive progress callbacks from a JS library like WebLLM), calling any Streamlit widget (st.progress, st.empty().caption, etc.) from inside that callback raises:

AttributeError: 'NoneType' object has no attribute 'get_name'

at streamlit/runtime/scriptrunner_utils/script_run_context.py, inside get_script_run_ctx().

I followed the documented workaround for calling Streamlit from background threads (capturing get_script_run_ctx() beforehand and calling add_script_run_ctx(threading.current_thread(), ctx) inside the callback), but it still fails at the same line - I suspect threading under Pyodide doesn't behave the way Streamlit's context-tracking expects (no real OS threads).

Minimal reproducer:
import asyncio
import streamlit as st
from streamlit.runtime.scriptrunner import add_script_run_ctx, get_script_run_ctx

st.title("Minimal repro: st.progress() inside a JS-invoked callback")

if st.button("Run"):
progress_bar = st.progress(0)
ctx = get_script_run_ctx()

def on_tick(value):
    add_script_run_ctx(__import__("threading").current_thread(), ctx)
    progress_bar.progress(value)

async def fake_async_work():
    import js  # type: ignore[import-not-found]
    from pyodide.ffi import create_proxy

    proxy = create_proxy(on_tick)
    # Simulate a JS library invoking our Python callback asynchronously,
    # the same way WebLLM's initProgressCallback does.
    await js.eval("new Promise(r => setTimeout(r, 50))")
    proxy(0.5)
    await js.eval("new Promise(r => setTimeout(r, 50))")
    proxy(1.0)
    proxy.destroy()

asyncio.run(fake_async_work())

Expected: the widget updates using the captured context, same as the documented threading pattern works in server-based Streamlit.

Actual: crashes with the AttributeError above, even with add_script_run_ctx.

Use case: wiring up initProgressCallback from @mlc-ai/web-llm (via import js + create_proxy) to show real download progress for an in-browser LLM - this is a common pattern for any JS library with an async progress callback.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions