Blocking tasks (sync or async) leads to ui frozen
Describe the bug
Stacked UI elements are not updated when a task is running, which blocks the main thread. This is the case for both async and sync code. For example, I want to create a spinner that pops up conditionally when I press a button, and place that spinner in a stacked configuration. Instead of showing up, the stacked element greys out. I can see the other element where the spinner is created, that it pops up. For async this is not the case.
This occurs on other elements as well, for instance markdown elements.
Environment
{ "marimo": "0.4.10", "OS": "Windows", "OS Version": "11", "Processor": "Intel64 Family 6 Model 126 Stepping 5, GenuineIntel", "Python Version": "3.12.2", "Binaries": { "Browser": "123.0.6312.123", "Node": "v14.16.0" }, "Requirements": { "click": "8.1.7", "importlib-resources": "missing", "jedi": "0.19.1", "markdown": "3.6", "pymdown-extensions": "10.7.1", "pygments": "2.17.2", "tomlkit": "0.12.4", "uvicorn": "0.29.0", "starlette": "0.37.2", "websocket": "missing", "typing-extensions": "4.9.0", "black": "24.3.0" } }
Code to reproduce
import marimo
__generated_with = "0.4.10"
app = marimo.App()
@app.cell
def __():
import marimo as mo
import asyncio
from time import sleep
return asyncio, mo, sleep
@app.cell
def __(mo):
get_do_something_async, set_do_something_async = mo.state(False)
get_do_something_sync, set_do_something_sync = mo.state(False)
return (
get_do_something_async,
get_do_something_sync,
set_do_something_async,
set_do_something_sync,
)
@app.cell
def __(mo, set_do_something_async):
button_do_async = mo.ui.button(label="Do something async", on_click=lambda v: set_do_something_async(True))
return button_do_async,
@app.cell
def __(mo, set_do_something_sync):
button_do_sync = mo.ui.button(label="Do something sync", on_click=lambda v: set_do_something_sync(True))
return button_do_sync,
@app.cell
def __(get_do_something_async, mo):
ui_do_async_spinner = mo.status.spinner(title="loading") if get_do_something_async() else mo.md("Waiting for async button press")
ui_do_async_spinner
return ui_do_async_spinner,
@app.cell
def __(get_do_something_sync, mo):
ui_do_sync_spinner = mo.status.spinner(title="loading") if get_do_something_sync() else mo.md("Waiting for sync button press")
ui_do_sync_spinner
return ui_do_sync_spinner,
@app.cell
def __(get_do_something_sync, mo):
ui_do_sync_pure_markdown = mo.md("""Running""") if get_do_something_sync() else mo.md("Waiting for sync button press")
ui_do_sync_pure_markdown
return ui_do_sync_pure_markdown,
@app.cell
async def __(asyncio, get_do_something_async, set_do_something_async):
_trigger_async = get_do_something_async()
async def do_something_async():
await asyncio.sleep(5)
print("Done")
if _trigger_async:
await do_something_async()
set_do_something_async(False)
return do_something_async,
@app.cell
def __(get_do_something_sync, set_do_something_sync, sleep):
_trigger_sync = get_do_something_sync()
def do_something_sync():
sleep(5)
print("Done")
if _trigger_sync:
do_something_sync()
set_do_something_sync(False)
return do_something_sync,
@app.cell
def __(button_do_sync, mo, ui_do_sync_spinner):
mo.vstack([button_do_sync, ui_do_sync_spinner])
return
@app.cell
def __(button_do_async, mo, ui_do_async_spinner):
mo.vstack([button_do_async, ui_do_async_spinner])
return
@app.cell
def __(button_do_sync, mo, ui_do_sync_pure_markdown):
mo.vstack([button_do_sync, ui_do_sync_pure_markdown])
return
if __name__ == "__main__":
app.run()
I'm not 100% sure i follow the use case - i'll try to digest it more. But in the meantime, have you see the mo.output.replace/mo.output.append/mo.output.clear? The allow you to update the cell output (replace/append/clear) before the cell finished.
e.g.
mo.output.replace(mo.status.spinner(title="loading"))
# do things
mo.ouput.replace(mo.md("First result: ", result)
# do more things
result
https://docs.marimo.io/api/outputs.html#cell-outputs
It's related to the example given in https://github.com/marimo-team/marimo/issues/1271, This works when the action (clicking a button), is inexpensive. However, in my use case I am calling a calculation engine, which takes seconds to return the results. Instead of showing the spinner, it doesn't show up and once the output returns it is gone. I'll take a look at the mo.output, maybe that's what I need..
@mrdobalina2k is this good to close out? not sure if you are still experiencing issues