St.session_state behaving strangely in some cases

Streamlit, version 1.12.2
Python 3.10.6 - 64bit
Windows 11

Below is an example script where a user interface is dynamically updated to display and handle an arbitrary number of widgets. Session_state is used to store information about the configured widgets between each time the script runs.

It normally functions as intended, but in some situations a bug appear.
To reproduce the bug, do the following (the st.writes are there for debugging purposes):

  1. Without typing anything into the text input, press the “Add data source” button.
    image

  2. Now, writhe anything into the upper text input. As soon as you press enter, the lower input gets updated as well.
    image

  3. The same happens if you type anything into the lower input.

  4. Now, add another data source, and delete one of the two already added.

  5. The application now functions as intended, and both the widgets and the session_state are correctly updated.

import streamlit as st

data_source_param = {
    'url' : '',
    'delete_btn': False,
    'query_btn': False
}


if 'data_sources' not in st.session_state:
    st.session_state['data_sources'] = [data_source_param]

def add_input():
    st.session_state['data_sources'].append(data_source_param)
    
def delete_input(source_ndx):
    st.session_state['data_sources'].pop(source_ndx)

def update_url(source_ndx):
    st.session_state['data_sources'][source_ndx]['url'] = st.session_state['url_' + str(source_ndx)]

def update_user_interface():
    st.write("Number of data sources: " + str(len(st.session_state['data_sources'])))
    source_ndx = 0
    for source in st.session_state['data_sources']:
        with st.container():
            col1, col2, col3 = st.columns([15, 5, 5])
            col1.text_input('API url', value= st.session_state['data_sources'][source_ndx]['url'], key= 'url_' + str(source_ndx), on_change=update_url, args= (source_ndx,), placeholder='Insert url' )
            col2.write('')
            col2.write('')
            col2.button('-', key='btn_' + str(source_ndx), on_click=delete_input, args=(source_ndx,))
        source_ndx += 1
            
st.set_page_config(page_title="UI tests", page_icon="📈")

st.markdown("# UI Tests")
st.write(
    """Dynamic user interface test"""
)

st.write(st.session_state)
update_user_interface()
st.button('Add data source', on_click= add_input)
st.write(st.session_state)

Any idea why this happens?

1 Like

I found the bug, and it was in my code…
I had forgotten to copy the dict when appending to the list it in the add_input function, hence the same reference was just duplicated in the list.
Why the same didn’t happen for the third list element, I still don’t know (point 4 and 5 in the test sequence in the original post).

1 Like