Streamlit session state reinitializes with old values after deleting

I have a clear button that deletes all variables in session state except auth variables with a function that calls

 # delete all except auth variables
    keysDelete = [string for string in sst.keys() if string not in ['userLoggedIn','userType', etc.]]
    for key in keysDelete:
        del sst[key]
    initSessionState()

where initSessionState() just sets up all needed variables again

for variable in variableList:
    saveVar(variable[0], variable[1])

where variableList is just a global list of values like [['id',''],['data',{}] and so on...]

but somehow some dictionaries are initialized with the old value after deleting, like:

{
"1":"<pandas.io.formats.style.Styler object at 0x7bf553c0d280>"
}

or other ones with a df instead of a Styler object.

Why does this happen and how can I clear these dict variables and set them up as empty dicts again?

I didnā€™t manage to make it happen for me by following your description here, so I think it is because of something that you didnā€™t tell us.

Iā€™m sorry, I donā€™t know what could cause this for some of the variables or what information is needed to reconstruct thisā€¦

I load data via an api (unfortunately I cant share the password details) and store some of them in the sst. For example, an xlsx file which is then displayed as table on the streamlit page. If the user wants to reload another dataset, then they delete the sst with the delete button (see above). If the user loads another dataset via api, I also initialize sst again (if the previous import get stuck) - so I delete all variables that are not auth variables and initialize them again (as empty dicts, I tried {} and dict()), but three of the dicts are not deleted. Two are pd.Styler objects (as shown above), and one is a dict that contains multiple entries with dfā€™s inside. All other variables (also dicts or whatever) get deleted as supposed to.

Do you have an idea what could cause this?

Ok, even weirderā€¦ I checked sst after deleting and then again after initializing. It seems that the variables are deleted correctly but then initialized with the old data again (only some of the variables, and only dicts). As mentioned in the first post, the variables are initialized by the initSessionState(), and the variableList is just a list like [['id',''],['files',{}] and so on...] but the content of some of the old entries is still stored somewhere? variableList is global.

unfortunately when testing other variables, I didnā€™t check before, there are more variables, that are initialized with the old value again (always dicts)

Use hardcoded data that you can share instead.

Have the xlsx file in your file system and read it from there. Or just create the table (pandas DataFrame?) by any other means. If there are sensible data, fake it. If it is big, make it smaller.

You are barely showing any code or data, instead you are writing a lot of text explaining what your code does and what your data looks like. But you have a bug here, and bugs are just your code not doing what you thing it does, which often is due to your data not being what you think it is. So we need to look at the code and the data, not at what you think about the code and the data.

Not reallyā€¦ I wrote that I cant reinitialize dict values as empty dicts after deleting them, thats all the information needed?

But I made an example to show the behaviour:

click on the first button ā†’ delete ā†’ the sst output after the st.info(ā€˜initializedā€™) shows the old data again
you can click the third button for example to see, that the info in the dictVar1 stays and that dictVar2 has both the old and new data while strVar, listVar, boolVar and dfVar are correctly reinitialized and filled with the new data (thats what the user would recognize)

Needed for what? You canā€™t do something that I can do. I have no idea why. I donā€™t know what to do with that information. I am as puzzled as you are.

I donā€™t quite understamd the purpose of the code and what output you would consider correct or incorrect, but your code is importing the three datasets even before the user has a chance to click a button, and that might be the root ot the issue. You probably want something like this:

st.button('first dataset', type='primary', on_click=importData, kwargs={'selectedDataset': 0})

instead of

st.button('first dataset', type='primary', on_click=lambda:importData(0))

Another issue is that you are mutating the dictVar1 and dictVar2 stored in variableList. So you are keeping the data there, because they are always the same object. I guess you want to create new objects instead.

    # dict 1 example
    if hasdict1data[selectedDataset]:
        sst.dictVar1 = {
            0: dict1data1[selectedDataset],
            1: dict1data2[selectedDataset]
        }
      
    # dict 2 example
    sst.dictVar2 = {}
    for img in dict2data[selectedDataset].keys():
        strings = dict2data[selectedDataset][img].split(' ')
        sst.dictVar2[img] = {'string1': strings[0],
                            'string2': strings[1],
                            'string3': strings[2]
                            }

I donā€™t think so, otherwise the sst after just loading the page would not display empty values?

Correct would be:

  • load the page ā†’ sst with empty variables initialized (this works)
  • load one dataset ā†’ sst has variables according to dataset (this works)
  • click on delete ā†’ sst is deleted and then re-initialized with empty values (as if you would load the page fresh) (deleting works, but re-initializing loads old values only for dicts)
  • load another dataset ā†’ sst has variables according to this dataset (works partly, since dicts have the old values again)

So, if I call sst.dictVar1[0] = ... Iā€™m mutating the variable dictVar1 in variableList - but If I call sst.dictVar1 = {0: ...} Iā€™m mutating dictVar1 in sst? Why is it not the same, I donā€™t call fn.dictVar1[0] = ... ?

Edit: I think I understand - sst.dictVar1[0] only points to dictVar1 in variableList and does not copy it?

Would it be useful to change

def saveVar(variableName, variable):
    if variableName not in sst:
        sst[variableName] = variable

to:

def saveVar(variableName, variable):
    if variableName not in sst:
        sst[variableName] = copy.deepcopy(variable)

to ensure, that variableList is not altered?

And you are right. I missunderstood how lambda works.

Looks like you managed to achieve it?

Yes, because sst.dictVar1 was assigned the same object that is in variableList.

Here you are just creating a new dictionary, different than the one in variableList.

Most likely, indeed it seems to work. The semantics of copy.deepcopy can be a bit tricky in a number of corner cases and it is less efficient, but I donā€™t think anything of that should be a concern here. I still prefer inmutability, though.

1 Like

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