Stateful app, don't understand why a session_state cannot be modified after the widget with a specific key is instantiated

hello
I have a simple code where I enter text in a text area, and when I hit enter, I want the text area to be cleared. I found how to do it but I don’t understand one of my my mistakes.
here is what I did in 5 steps to find the solution, and don’t understand my mistake at step 4

At the beginning, I had this and the text area was never cleard when I hit enter

import streamlit as st
input = st.text_input('enter text, will be stored in "input"')
st.write(f'you wrote (display what is in input): {input}')

so I tried this case 2:

import streamlit as st
st.session_state.input = 'case2'
st.write(f"input in session_state : {st.session_state.input}")
st.session_state.input = st.text_input('enter text, will be stored in "input"')
st.write(f'you wrote (display what is in input): {st.session_state.input}')

when I hit enter, the text area was never cleard but also, I noticed on the op of my page that is awways showed "case2 when i wanted to displayed the input value in session_state. however on the bottom of my page, the input value had the text i wrote in the area.

I understand that when I hit enter, the app restart again, so that is why I always have “case2” at the op of my page.
Am I correct?

so i tried this case 3:

import streamlit as st
if 'input' not in st.session_state:
    st.session_state.input = 'case3'
st.write(f"input in session_state : {st.session_state.input}")
st.session_state.input = st.text_input('enter text, will be stored in "input"')
st.write(f'you wrote (display what is in input): {st.session_state.input}')

when i launch the app, at the top of my page, I have “case3”. But when I enter the text ‘hello’ and hit enter, at the top of my page, I have nothing, and at the bottom, I have “hello”.
Then if I enter “bye” and hit enter : at the top of my page, I have 'hello", and at the bottom, I have “bye”.

I think this confirmed that when hit enter, the app restart again.

so I tried this case 4

import streamlit as st
if 'input' not in st.session_state:
    st.session_state.input = 'start_4'
if 'area' not in st.session_state:
    st.session_state.area = ''

st.write(f"input in session_state : {st.session_state.input}")
st.write(f"area in session_state : {st.session_state.area}")

st.session_state.input = st.text_input('enter text', key='area')
st.write(f"you wrote (display what is in input): {st.session_state.input}")
st.session_state.area = ''

I want my widget named “area” to be cleared when I hit enter, so I have to put the code about the clearing at the end right?
I don’t understand this error:

StreamlitAPIException: st.session_state.area cannot be modified after the widget with key area is instantiated.

But I finally tried this :

if 'input' not in st.session_state:
    st.session_state.input = 'case5'

if 'area' not in st.session_state:
    st.session_state.area = ''

st.write(f"input in session_state : {st.session_state.input}")
st.write(f"area in session_state : {st.session_state.area}")

def submit():
    st.session_state.input = st.session_state.area
    st.session_state.area = ''

st.text_input('enter text, will be stored in "input"', key='area', on_change=submit)
st.write(f'you wrote (display what is in input): {st.session_state.input}')

and it worked but i’m confused with he error message at step 4.

can you help me?

hii @linuxmint

In Step 4, the issue is related to the fact that the st.text_input widget is being assigned to st.session_state.input , and Streamlit doesn’t allow modifying a widget after it has been instantiated. When you do:

st.session_state.input = st.text_input('enter text', key='area')

You’re trying to modify st.session_state.input after it’s already been instantiated by the st.text_input widget. This is not allowed, and that’s why you see the StreamlitAPIException .

Hello
this is where i am confused
in step 4 my code is

import streamlit as st
if 'input' not in st.session_state:
    st.session_state.input = 'start_4'
if 'area' not in st.session_state:
    st.session_state.area = ''

st.write(f"input in session_state : {st.session_state.input}")
st.write(f"area in session_state : {st.session_state.area}")

st.session_state.input = st.text_input('enter text', key='area')
st.write(f"you wrote (display what is in input): {st.session_state.input}")
st.session_state.area = ''

you said i’m trying to modify st.session_state.input after it’s already been instantiated by the st.text_input widget.
I’m confused because i don’t see when does the st.text_input widget instantiate
st.session_state.input : on the contrary it looks like the modification and the instantiation is done at the same time.

and in step 5 where everything is ok, when I look at this:

st.text_input('enter text, will be stored in "input"', key='area', on_change=submit)

it seems tha t the function submit is also modifying st.session_state.input on the same time as the instantiation

I’m a beginner with streamlit, sorry if my question is dumb.
maybe it’s because I’m not familiar with callbacks and the on_change stuff

The problematic assignment is st.session_state.area = "" and it is executed after you call st.text_input('enter text', key='area'), not at the same time.

How so? After the widget has been instantiated, you can wait hours before submitting of you want.

By the time you press Enter and submit is called, your script has already run from top to bottom, so it doesn’t count as part of that run. The limitation only applies to a single run of the main script.

thank you

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