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()
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'
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.
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)