Thank you for taking the time to try to understand my problem.
a) I was unable to develop a test case that illustrates my problem outside of my context.
b) My context is complex. I have a Streamlit application with three columns: in the left and right columns, there are two menus (which are external components that I defined), and in the middle column, there is another external component (defined by me) that represents a tree structure.
When selecting an option from the right menu, I call a function that creates an element that will appear in the middle tree structure.
Until Streamlit version 1.34.0, everything was fine; I didn’t observe any particular side effects.
Using Streamlit version 1.38.0, the problem appeared: the function that creates an element is often called twice, but sometimes only once, as before. Using logs, I realized that the script undergoes a “rerun” in the middle of the function that creates the element.
A piece of code showing how the “kairos_create_node” function is called:
m2 = MENU(menu=menu, height=600, mode='inline', theme=theme['streamlit_theme'], id='options')
if m2.get():
st.session_state.nodemenu = m2.get()
logger.debug(f'Nodemenu option: {st.session_state.nodemenu}')
if 'nodemenu' not in st.session_state: st.session_state.nodemenu = None
if st.session_state.nodemenu == "Create node": kairos_create_node()
Now the “kairos_create_node” function:
def kairos_create_node():
nodesdb = st.session_state.nodesdb
node = st.session_state.node
logger.info(f'Creating a new node into {nodesdb} and attaching node to {node}')
command = f'kairos -s createnode --nodesdb {nodesdb} --id {node}'
act = run(command)
logger.debug(act)
if 'success' in act and act['success']:
st.session_state.treeupdated = True
st.session_state.nodemenu = None
run_again()
else: st.error(act['message'])
and now the “run function”:
def run(cmd, pattern=None, gson=True):
if 'cptrun' not in st.session_state: st.session_state.cptrun = -1
st.session_state.cptrun = st.session_state.cptrun + 1
if st.session_state.cptrun > 0: logger.critical(f'Command launched several times: {cmd}')
logger.debug(cmd)
child = pexpect.spawn(cmd, encoding='utf8', timeout=None)
x = ''.join([line for line in child])
logger.debug(x)
st.session_state.cptrun = -1
if gson:
result = json.loads(x)
if pattern: result = jq(pattern).transform(result)
else:
result = x
return result
The peculiarity of the “run” function called by “kairos_create_node” is that it uses “pexpect.spawn,” which is equivalent to “subprocess.check_output” and, by the way, causes the same issue. Here, we execute a command through a subprocess and want to capture the result in a variable.
The logs set up in my context show that the “rerun” initiated by Streamlit version 1.38.0 occurs inside the “run” function, likely due to the specifics related to the use of a subprocess.
An exemple of trace illustrating the problem:
2024-08-29 09:57:22.025 | DEBUG | __main__:<module>:66 - Selected node : 1
2024-08-29 09:57:38.928 | DEBUG | __main__:<module>:7 - Generating the KAIROS page ...
2024-08-29 09:57:38.931 | DEBUG | __main__:<module>:35 - Mainmenu option: None
2024-08-29 09:57:38.935 | DEBUG | __main__:<module>:66 - Selected node : 1
2024-08-29 09:57:38.936 | DEBUG | pages.functions.definitions:run_again:23 - Restarting SCRIPT ...
2024-08-29 09:57:39.005 | DEBUG | __main__:<module>:7 - Generating the KAIROS page ...
2024-08-29 09:57:39.009 | DEBUG | __main__:<module>:35 - Mainmenu option: None
2024-08-29 09:57:39.012 | DEBUG | __main__:<module>:66 - Selected node : 1
2024-08-29 09:57:39.013 | DEBUG | __main__:<module>:121 - Nodemenu option: Create node
2024-08-29 09:57:39.013 | INFO | pages.functions.definitions:kairos_create_node:178 - Creating a new node into kairos_user_admin and attaching node to 1
2024-08-29 09:57:39.014 | DEBUG | pages.functions.definitions:run:495 - kairos -s createnode --nodesdb kairos_user_admin --id 1
2024-08-29 09:57:39.548 | DEBUG | __main__:<module>:7 - Generating the KAIROS page ...
2024-08-29 09:57:39.552 | DEBUG | __main__:<module>:35 - Mainmenu option: None
2024-08-29 09:57:39.560 | DEBUG | __main__:<module>:66 - Selected node : 1
2024-08-29 09:57:39.563 | INFO | pages.functions.definitions:kairos_create_node:178 - Creating a new node into kairos_user_admin and attaching node to 1
2024-08-29 09:57:39.563 | CRITICAL | pages.functions.definitions:run:494 - Command launched several times: kairos -s createnode --nodesdb kairos_user_admin --id 1
2024-08-29 09:57:39.564 | DEBUG | pages.functions.definitions:run:495 - kairos -s createnode --nodesdb kairos_user_admin --id 1
2024-08-29 09:57:39.813 | DEBUG | pages.functions.definitions:run:498 - {
"data": {
"created": "2024-08-29 09:57:39.745",
"datasource": {
"cache": {},
"producers": [],
"type": "N"
},
"icon": "N",
"id": 279,
"name": "2024-08-29 09:57:39.743",
"status": "ACTIVE"
},
"success": true
}
2024-08-29 09:57:40.214 | DEBUG | pages.functions.definitions:run:498 - {
"data": {
"created": "2024-08-29 09:57:40.167",
"datasource": {
"cache": {},
"producers": [],
"type": "N"
},
"icon": "N",
"id": 280,
"name": "2024-08-29 09:57:40.165",
"status": "ACTIVE"
},
"success": true
}
2024-08-29 09:57:40.315 | DEBUG | pages.functions.definitions:kairos_create_node:181 - {'data': {'created': '2024-08-29 09:57:40.167', 'datasource': {'cache': {}, 'producers': [], 'type': 'N'}, 'icon': 'N', 'id': 280, 'name': '2024-08-29 09:57:40.165', 'status': 'ACTIVE'}, 'success': True}
2024-08-29 09:57:40.315 | DEBUG | pages.functions.definitions:run_again:23 - Restarting SCRIPT ...
2024-08-29 09:57:40.406 | DEBUG | __main__:<module>:7 - Generating the KAIROS page ...
2024-08-29 09:57:40.409 | DEBUG | __main__:<module>:35 - Mainmenu option: None
Some explanation:
At the beginning og the script I have one instruction which shows when the script is rerun:
In the log we have:
2024-08-29 09:57:40.406 | DEBUG | main::7 - Generating the KAIROS page …
Sometimes we have:
2024-08-29 09:57:38.936 | DEBUG | pages.functions.definitions:run_again:23 - Restarting SCRIPT …
2024-08-29 09:57:39.005 | DEBUG | main::7 - Generating the KAIROS page …
This case occurs when st.rerun() has been called explicitely by the script.
BUT when
2024-08-29 09:57:39.005 | DEBUG | main::7 - Generating the KAIROS page …
is not preceded by
2024-08-29 09:57:38.936 | DEBUG | pages.functions.definitions:run_again:23 - Restarting SCRIPT …
that means that the rerun has been initiated by Streamlit itself…
So when you analyze the log, you are convinced that the “rerun” initiated by streamlit occurs between these instructions appearing in the ‘run’ function:
logger.debug(cmd)
child = pexpect.spawn(cmd, encoding=‘utf8’, timeout=None)
x = ‘’.join([line for line in child])
logger.debug(x)
So the question is: what are the updates done in Streamlit code between 1.34.0 and 1.38.0.
I’m convinced that one of these updates are in strong relationship with the problem I observed.
Of course, I can try each Streamlit version 1.35.0, … to isolate the version showing the change but not yet done…
An other information: I tried to put the “st.session_state.nodemenu = None” earlier in the script but the side effect occurs differently.
There is something associated with the subprocess that causes Streamlit to restart the script.
It would be great if Streamlit provided a log explaining the reason for a “rerun.”