Fixing position of st.spinner

I would like to put all my loading messages in one set location.

My app has a few expanders, utilizes the sidebar, and makes great use of caching via st.cache and st.experimental_memo. Often times, spinners and messages get lost because they appear in the app in the order the components are called.

I’ve tried to reserve a spot in the sidebar where all the temporary messages would be shown and disappear once the function finishes.

loading_placeholder = st.empty()

# Some code
with loading_placeholder.spinner("Calculating"):
    # Function that takes some time

This is not currently possible and when run is met with the following error:
streamlit.errors.StreamlitAPIException: Method \spinner()` does not exist for `DeltaGenerator` objects. Did you mean `st.spinner()`?`

We can acheive the wanted behavior with the following:

loading_placeholder = st.empty()

# Some code
with loading_placeholder:
    with loading_placeholder.spinner("Calculating"):
        # Function that takes some time

This works, but requires an extra line and an extra indent. Is there a better / shorter way to acheive this?

1 Like

Quite an old post but adding 2 cents for someone who might stumble upon it:
It should be possible to put both context managers under a “single roof”, comma separated, like:

# Some code
with placeholder, placeholder.spinner("Calculating"):
    #Function that takes time

@ya55en both workarounds don’t work for me.
In which python version does this work?

I have the same problem as @gustavz. Either workaround results in StreamlitAPIException: Method spinner() does not exist for DeltaGenerator objects. Did you mean st.spinner()?

This was working for me:

    placeholder = st.empty()
    with placeholder, st.spinner("Calculating"):
        # code to wait

Similarly, to position the spinner into a container, the following worked for me:

container = st.container()
with container:
    with st.spinner("Text"): # so not as an element of container, but just within the container
        # do something

You can define the container at the desired point in the streamlit execution order.

Within an st.expander, the following worked for me…

with expander, st.spinner("Calculating"):
    #Function that takes time