Strange and unacceptable (I suppose) cache behaviour

Hi all,

I’ve a page with notification and checkboxes that are automatically created depending on some properties. The page is quite long and quite expensive in terms of computation (9 seconds) so it should be quite “heavy” for streamlit I suppose.
I know the image is not readable but it’s just to give you an idea

All the code that generates this page is within a switch over a session state variable.

if st.session_state['status'] == 1:
     creating all the elements that fills this page -> this is the "heavy" part
     if st.button("Go"):
           st.session_state['status'] = 2
           st.experimental_rerun()

if st.session_state['status'] == 2:
     other dumb action to be performed (imagine just an st.write("Hello world"))

I know that once I press go, all the code before the button is executed another time and I’m fine with that. But after the st.experimental rerun is launched I’m sure that the heavy code is not executed anymore.

Now the question…

Could someone explain to me how it’s possible that I see all the old elemnts (of [status] == 1) disabled and completely ruining the UI while I’m executing code in [‘status’] == 2 ??
Makes totally no sense to me, maybe it’s something that should be taken out from the cache?
This is a screenshot of the situation

In the screenshot it’s more trasnaparent than it looks within the page (the UI is worste than the screen)

Thank you,
Lorenzo

Here’s a little sample code so you can see how Streamlit fades out the page while it’s computing the delta for the new load. This is the default behavior. If you need a clean page wipe, you can put your whole page in a container within an empty element so you have a means to clean the slate.

import streamlit as st
import random
import time

slate = st.empty()
body = slate.container()

def clean ():
    slate.empty()

def fizz_buzz (n):
    word = []
    if n%5 == 0:
        word.append('fizz')
    if n%7 == 0:
        word.append('buzz')
    if n%11 == 0:
        word.append('pop')
    word = '-'.join(word)
    if word != '':
        st.write(word)

with body:
    st.button('Rerun')
    st.button('Wipe and Rerun', on_click=clean)
    
    cols = st.columns(5)

    col = random.randint(0,4)

    with(cols[col]):
        start = random.randint(1,5*7*11)
        for i in range(start,start+33):
            fizz_buzz(i)
            time.sleep(.1)

Hi,

This is not working to me, I still see everything disabled) as before:

This is just a little section of what I have (code that is not being executed but it’s still visible)

If you implemented st.empty() as in my example, can you share your code for that?

In 10 minutes I’ll reply. Thank you

At the moment I have something like:

slate = st.empty()
body = slate.container()
def clean ():
    slate.empty()

with body:
    if st.session_state['y'] == 1:
          fill the page ("heavy code")
          
          if st.button("Save", onclick=clean):
                st.session_state['y'] = 2
                st.session_state['toBeProfiled'] = True
                st.experimental_rerun()
          
[out of the body now]
if st.session_state['y'] == 2:
      some code

after I click the save button all the code until there is rerun once (intrisically caused by streamlit, is not executed my command rerun, and ok) but then after i update to 2 [‘y’] and perform the rerun that I launched I correctly enter in the other session state but I still have that UI problem

As written:

  1. Someone clicks the save button
  2. The contents are cleared
  3. The page goes straight to rerun and not to updating your y key
  4. The heavy computation is redone
  5. It gets to the button and sees it is True
  6. Then y is updated to 2 and the page reloads, skipping over the heavy computation

Solution: the key update needs to happen in the callback. I’ve left the example with the empty container, but you may not need it at all if there isn’t anything else substantial on the page. Just getting that key updated where intended would be all you need. Sorry I didn’t focus on that first.

import streamlit as st
import time

slate = st.empty()
body = slate.container()

if 'y' not in st.session_state:
    st.session_state.y = 1

def clean ():
    slate.empty()
    st.session_state['y'] = 2
    st.session_state['toBeProfiled'] = True

with body:
    if st.session_state['y'] == 1:
          expensive = st.progress(0)
          for i in range(1,101):
            expensive.progress(i)
            time.sleep(.05)          
          st.button("Save", on_click=clean)

if st.session_state['y'] == 2:
      st.write('The output has been saved.')

MAAAAAAAAAAAAAAAAAN

You’ve completely solved my issue.
(I added an st.eperimental_rerun as last in the clean function)

I owe you a part of my thesis’ mark :heart:

You won’t need the rerun inside the clean function (and in fact, that will throw an error). When a function is executed as a callback, it will always be followed by a rerun. :slight_smile: (If you call the function somewhere else manually, you can add a rerun after the function if need be.) When you try to manually rerun inside of a callback function, Streamlit doesn’t like it since a rerun is already queued up.