Session_state: del a value

I would like to better understand the logic behind session_state because I am in trouble. I noticed that if I put a dictionary in session_state, let’s say mem, then I delete a key directly, for example:

del st.session_state.mem[‘ingr’]

if I enter the same key again through a widget, the previous value associated with that key reappears again, despite having deleted it before.
How do you permanently delete a value in a data structure stored in session_state?

Hi @Fabio_Pasquarella

Thanks for opening this issue.

if I enter the same key again through a widget, the previous value associated with that key reappears again, despite having deleted it before.

Can you share a minimal code example so that I can reproduce the problem?

Thanks,
Abhi

it’s not exactly an easy code to follow. Basically the user enters a recipe in the form of a dictionary in which each ingredient corresponds to a value. The user must be able to go back to the recipe, add, remove and change values.

################ FUNCTION ################

def changed_ingr():

if st.session_state.ricetta_memoria_changed:  

    if len(st.session_state.ricetta_memoria_changed)>len(st.session_state.ricetta_memoria[1]):

        ingr=set(st.session_state.ricetta_memoria_changed)-set(list(st.session_state.ricetta_memoria[1].keys()))

        ingr=list(ingr)[0]


        st.session_state.ricetta_memoria[1][ingr]=0.0 



    elif len(st.session_state.ricetta_memoria_changed)<len(st.session_state.ricetta_memoria[1]):


        ingr=set(list(st.session_state.ricetta_memoria[1].keys()))-set(st.session_state.ricetta_memoria_changed)
        

        ingr=list(ingr)[0]


        del st.session_state.ricetta_memoria[1][ingr] # fai l'update della ricetta in memoria

################### MAIN ##################

if "ricetta_memoria" not in st.session_state:

    st.session_state.ricetta_memoria = ["",ricetta,dati_temp_immessi]




select=st.multiselect('Scegli gli ingredienti della tua ricetta',df.index.tolist(),on_change=changed_ingr,
default=list(st.session_state.ricetta_memoria[1].keys()), key="ricetta_memoria_changed")




for key in list(st.session_state.ricetta_memoria[1].keys()):

    st.session_state.ricetta_memoria[1][key]=st.number_input(key,min_value=0.,
    value=st.session_state.ricetta_memoria[1][key])

@Fabio_Pasquarella

For reference, every widget with a key is automatically added to Session State. Please see our docs:
https://docs.streamlit.io/en/stable/session_state_api.html#session-state-and-widget-state-association

I made some assumptions about inputs to be able to run your code. The code below allows me to add, remove and update ingredients

import streamlit as st


ricetta = {
    'rice': 3.0,
    'cheese': 5.0
}

dati_temp_immessi = 'x'


def changed_ingr():
    if st.session_state.ricetta_memoria_changed:
        if len(st.session_state.ricetta_memoria_changed) > len(st.session_state.ricetta_memoria[1]):
            ingr = set(st.session_state.ricetta_memoria_changed) - set(list(st.session_state.ricetta_memoria[1].keys()))
            ingr = list(ingr)[0]
            st.session_state.ricetta_memoria[1][ingr] = 0.0

        elif len(st.session_state.ricetta_memoria_changed) < len(st.session_state.ricetta_memoria[1]):
            ingr = set(list(st.session_state.ricetta_memoria[1].keys())) - set(st.session_state.ricetta_memoria_changed)
            ingr = list(ingr)[0]
            del st.session_state.ricetta_memoria[1][ingr]  # fai l'update della ricetta in memoria


if "ricetta_memoria" not in st.session_state:
    st.session_state.ricetta_memoria = ["",ricetta,dati_temp_immessi]


select = st.multiselect('Scegli gli ingredienti della tua ricetta',
    ['rice', 'cheese', 'apples', 'water'],on_change=changed_ingr,
    default=list(st.session_state.ricetta_memoria[1].keys()), 
    key="ricetta_memoria_changed"
)


for key in list(st.session_state.ricetta_memoria[1].keys()):
    st.session_state.ricetta_memoria[1][key] = st.number_input(key, min_value=0., value=0.0)

Note that I have a suggestion for a change in the following line in your code

BEFORE

st.session_state.ricetta_memoria[1][key] = st.number_input(key,min_value=0., value=st.session_state.ricetta_memoria[1][key])

The code above can lead to an off by one error. So I would recommend setting value=0.0

AFTER

st.session_state.ricetta_memoria[1][key] = st.number_input(key,min_value=0.,value=0.0)

thank you for your reply Abhi, but your code doesn’t preserve state (ingredients and values):

import streamlit as st

my_page = st.sidebar.radio(‘Section’, [‘Recipe’,‘Other’])

if my_page == ‘Recipe’:

ricetta = {
    'rice': 3.0,
    'cheese': 5.0
}

dati_temp_immessi = 'x'



def changed_ingr():
    if st.session_state.ricetta_memoria_changed:
        if len(st.session_state.ricetta_memoria_changed) > len(st.session_state.ricetta_memoria[1]):
            ingr = set(st.session_state.ricetta_memoria_changed) - set(list(st.session_state.ricetta_memoria[1].keys()))
            ingr = list(ingr)[0]
            st.session_state.ricetta_memoria[1][ingr] = 0.0

        elif len(st.session_state.ricetta_memoria_changed) < len(st.session_state.ricetta_memoria[1]):
            ingr = set(list(st.session_state.ricetta_memoria[1].keys())) - set(st.session_state.ricetta_memoria_changed)
            ingr = list(ingr)[0]
            del st.session_state.ricetta_memoria[1][ingr]



if "ricetta_memoria" not in st.session_state:
    st.session_state.ricetta_memoria = ["",ricetta,dati_temp_immessi]


select = st.multiselect('Scegli gli ingredienti della tua ricetta',
    ['rice', 'cheese', 'apples', 'water'],on_change=changed_ingr,
    default=list(st.session_state.ricetta_memoria[1].keys()),
    key="ricetta_memoria_changed"
)


for key in list(st.session_state.ricetta_memoria[1].keys()):
    st.session_state.ricetta_memoria[1][key] = st.number_input(key, min_value=0., value=0.0)

else:

st.write("another section")

@Fabio_Pasquarella : To be more precise, do you mean that toggling between Recipe and Other doesn’t preserve the state of the number_input widgets?

yes @abhi, I need to preserve the whole recipe (ingredients and values)

I see, in that case you can consider adding a callback to update the value of ingredients as follows:

    def update_value(key):
        st.session_state.ricetta_memoria[1][key] = st.session_state[key]


    for key in list(st.session_state.ricetta_memoria[1].keys()):

        st.number_input(key, min_value=0.,
            value=st.session_state.ricetta_memoria[1][key], key=key,
            on_change=update_value, args=(key,)
        )

4 Likes

@abhi thank you very much for your time!

@Fabio_Pasquarella : Happy to help :slight_smile: