Session_state resets when i press a button

Summary

I am developing an app what is using multiple windows. I change the windows with a session_state variable and a condition.
I experienced that every time I reset the window to the initial one, the session_state is being deleted.
As far as I understood the whole meaning of the session_state, it should be used for store variables instead of caching. And a widget should have the state what is declared on the session_state (like it is working with the mirrored widgets case)
I prepared an example code for showing this problem. There are multiple widget, a text input with default value of “ABC”, a checkbox, and 2 mirrored number input. After I change window to the second one, the session state keeps its values, but when I change it back, de values are deleted from the session_state.

Do you have any ideas of what am I doing wrong, or is it a bug, or how could I fix this?

Thank you for your help in advance!

Steps to reproduce

Code snippet:

import streamlit as st

st.set_page_config(layout="wide", page_title="Automatic Resolution Evaluation")


def main():
    
    if "window" not in st.session_state:
        
        st.session_state.window = "init"
        st.session_state.txt = "ABC"
    
    st.write(st.session_state)
        
    
    if st.session_state.window == "init":
        st.text_input("TEXT INPUT",
                      key="txt")
        
        st.number_input("Number",
                       key="num",
                       on_change=double)
        
        st.number_input("Double of number",
                        key="double",
                        on_change=half)
        
        st.checkbox("Checkbox", key="checkbox")
        
        st.button("Change window", on_click=changeWindow)
        
        
        
    elif st.session_state.window == "second":
        st.write("Contents of 2nd window...")
        st.button("Change window", on_click=changeWindow)
        
def half():
    
    st.session_state.num = st.session_state.double / 2

def double():
    
    st.session_state.double = st.session_state.num * 2

def changeWindow():
    if st.session_state.window == "init":
        st.session_state.window = "second"
        
    elif st.session_state.window == "second":
        st.session_state.window = "init"



if __name__ == "__main__":
    
    main()

Debug info

  • Streamlit version: 1.26.0
  • Python version: 3.11.4
  • Using conda
1 Like

Hi @osvay

It seems that the session state variables were defined within individual functions thus making it a local variable within those functions rather than a global state variable.

Could you try refactoring the code such that the session state variables are defined outside. Also, if statements should be used to define every session state variables for the first time.

if 'key' not in st.session_state:
    st.session_state['key'] = 'value'

More info in the Docs:

Hope this helps!

Just to focus in on the session_state.txt case:

  1. You’re only populating it IF window is not set
  2. If window is set, it doesn’t get populated
  3. You are also putting it as the key of a widget
  4. If that widget disappears, that key will be removed from session state automatically. (this behavior can be annoying, though there are some good reasons for it. We are looking into options for making keys persist even if widgets are gone, since that is nice in some cases).

That #4 is most of the issue you are experiencing, I believe.

There is a hack to get around this, which is to explicitly set the session state. It’s weird, but it works.

    for k, v in st.session_state.items():
        st.session_state[k] = v

If you add this at the bottom of your “change window” calback, then the problem goes away.

2 Likes

Thank you for the quick response @dataprofessor !

After refactoring the code the behavior remained the same. It seems that creating widgets with key argument deletes the session_state’s element which has the same key. But this is a bit weird because in this case the mirrored widgets couldn’t work…
I tried some things, and with this code, only 2 variables stay in session_state after returning the initial window: the “window” and the "“txtList”. The rest is deleted.

import streamlit as st

st.set_page_config(layout="wide", page_title="TEST")

   
        
def half():
    
    st.session_state.num = st.session_state.double / 2

def double():
    
    st.session_state.double = st.session_state.num * 2

def changeWindow():
    
    if st.session_state.window == "init":
        st.session_state.window = "second"
        
    elif st.session_state.window == "second":
        st.session_state.window = "init"
    

def saveTxtList():
    
    st.session_state.txtList = list(st.session_state.txt)


if __name__ == "__main__":

    if "window" not in st.session_state:
        st.session_state.window = "init"
        
        if "txt" not in st.session_state:
            st.session_state.txt = "ABC"
    
    st.write(st.session_state)
        
    
    if st.session_state.window == "init":
        
        st.text_input("TEXT INPUT",
                      key="txt",
                      on_change=saveTxtList)
        
        st.number_input("Number",
                       key="num",
                       on_change=double)
        
        st.number_input("Double of number",
                        key="double",
                        on_change=half)
        
        st.checkbox("Checkbox", key="checkbox")
        
        st.button("Change window", on_click=changeWindow)  
        
        
    elif st.session_state.window == "second":
        st.write("Contents of 2nd window...")
        st.button("Change window", on_click=changeWindow)
    

Thank you @blackary, now it works fine.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.