arnaudmiribel/streamlit-extras

๐Ÿ› [BUG] - Stateful Chat errors out with `AttributeError: 'ScriptRunContext' object has no attribute 'dg_stack'`

Opened this issue ยท 5 comments

Description

I'm trying a the minimal example.
Python version: 3.12.7

Reproduction steps

1. Take the minimal example from https://arnaudmiribel.github.io/streamlit-extras/extras/stateful_chat/
2. Enter anything into the chat input and send it
3. It falters early at the `add_message("user", prompt, avatar="๐Ÿง‘โ€๐Ÿ’ป")` line.

Screenshots

No response

Logs

2024-11-15 08:32:45.762 Uncaught app exception
Traceback (most recent call last):
  File "/Users/csabatoth/pdev/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/exec_code.py", line 88, in exec_func_with_error_handling
    result = func()
             ^^^^^^
  File "/Users/csabatoth/pdev/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 579, in code_to_exec
    exec(code, module.__dict__)
  File "/Users/csabatoth/repos/AOA/frontend/app.py", line 48, in <module>
    add_message("user", prompt, avatar="๐Ÿง‘โ€๐Ÿ’ป")
  File "/Users/csabatoth/pdev/lib/python3.12/site-packages/streamlit/runtime/metrics_util.py", line 410, in wrapped_func
    result = non_optional_func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/csabatoth/pdev/lib/python3.12/site-packages/streamlit_extras/stateful_chat/__init__.py", line 75, in add_message
    active_dg = _active_dg()
                ^^^^^^^^^^^^
  File "/Users/csabatoth/pdev/lib/python3.12/site-packages/streamlit_extras/stateful_chat/__init__.py", line 36, in _active_dg
    if ctx and len(ctx.dg_stack) > 0:
                   ^^^^^^^^^^^^
AttributeError: 'ScriptRunContext' object has no attribute 'dg_stack'

Version of streamlit

1.39.0

Version of streamlit-extras

0.5.0

Maybe @lukasmasuch has an idea? Internal imports changed?

I can see that there's some care about how this dg_stack is accessed


So maybe this is some kind of a Streamlit version issue? Even though I would not expect much change between v1.37 and v1.39, but are we relying on some internal feature which could have changed?

Trying to debug this. I put a print(dir(ctx)) on line 3 after

['annotations', 'class', 'dataclass_fields', 'dataclass_params', 'delattr', 'dict', 'dir', 'doc', 'eq', 'firstlineno', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'match_args', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'replace', 'repr', 'setattr', 'sizeof', 'static_attributes', 'str', 'subclasshook', 'weakref', '_active_script_hash', '_enqueue', '_experimental_query_params_used', '_has_script_started', '_production_query_params_used', '_set_page_config_allowed', 'active_script_hash', 'command_tracking_deactivated', 'current_fragment_delta_path', 'current_fragment_id', 'cursors', 'enqueue', 'ensure_single_query_api_used', 'form_ids_this_run', 'fragment_ids_this_run', 'fragment_storage', 'gather_usage_stats', 'has_dialog_opened', 'main_script_path', 'mark_experimental_query_params_used', 'mark_production_query_params_used', 'new_fragment_ids', 'on_script_start', 'page_script_hash', 'pages_manager', 'query_string', 'reset', 'run_with_active_hash', 'script_requests', 'session_id', 'session_state', 'set_mpa_v2_page', 'tracked_commands', 'tracked_commands_counter', 'uploaded_file_mgr', 'user_info', 'widget_ids_this_run', 'widget_user_keys_this_run']

I don't see any dg or stack

This was changed in a recent release :( The new way to use it is via the get_last_dg_added_to_context_stack method:

https://github.com/streamlit/streamlit/blob/5290639fa9c1ae7c573ff51858e285e007a5e6ea/lib/streamlit/delta_generator_singletons.py#L190

The fix might be something like this (haven't tested it yet):

def _active_dg():
    try:
       from streamlit.delta_generator_singletons import get_last_dg_added_to_context_stack
       
       return get_last_dg_added_to_context_stack()
    except ModuleNotFoundError:  # from streamlit < 1.39
       pass

    try:
        from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx
    except ModuleNotFoundError:  # from streamlit > 1.37
        from streamlit.runtime.scriptrunner_utils.script_run_context import (
            get_script_run_ctx,
        )

    ctx = get_script_run_ctx()
    if ctx and len(ctx.dg_stack) > 0:
        return ctx.dg_stack[-1]

What I was trying to go along the existing code:

from streamlit.delta_generator_singletons import context_dg_stack

...
    dg_stack = context_dg_stack.get()
    if dg_stack and len(dg_stack) > 0:
        return dg_stack[-1]

Your solution seems to be shorter / better.