A library to easily synchronize sessions between themselves or on local drive for later reuse.
Link to initial topic on Streamlit forum.
import streamlit as st
import streamlit_sync
CACHE_DIR = "./.st_sync_cache"
room_name = streamlit_sync.select_room_widget(CACHE_DIR)
with streamlit_sync.sync(room_name, cache_dir=CACHE_DIR):
y = st.slider("Select a value")
st.write(y, "squared is", y * y)
A more complete example app can be found in ./toy_example.py.
The initial goal was to be able to share a dashboard on which anyone can interact. Each user sees the effects of other users on their dashboard.
Potential use cases are:
- It can be a way to "save" locally a streamlit session. Caching is done using DiskCache library.
- In a meeting/presentation, it can be a solution to avoid having 1 user sharing its screen to others and making all the manipulations.
- Small games or chats can be implemented this way.
- etc.
pip install streamlit-sync
streamlit-sync
is using internal APIs of Streamlit that are not meant to be public. It is not guaranteed that it will work on future versions. All calls to internal APIs are grouped in ./streamlit_sync/st_hack.py.streamlit-sync
is not designed to be particularly efficient. A synced version of your dashboard is an even better incentive to use streamlit caching.- Robustness of this library is not guaranteed when used with a lot of concurrent sessions.
streamlit-sync
is not well covered by tests. It would require to have end-to-end tests with several sessions but that's not done.
(streamlit-server-state) is another library doing a similar job. It is used to have server-side state. The idea of streamlit-sync
is to sync the widgets as well.
Each room uses its own lock (from python threading
lib). Only 1 session per room can read/write the values of the room at a time. I don't know how this would impact the usability if a large amount of sessions are connected to the same room.
Each room keeps in memory the latest snapshot of values with a timestamp. A session can only update a value if it already had the latest data. This means if 2 different sessions make an action on the dashboard at the same time, 1 action will most likely be lost.
Sessions can be persisted on disk. To do so, use the optional cache_dir
argument. By default, sessions are synced only in memory.
import streamlit as st
import streamlit_sync
with streamlit_sync.sync("room", cache_dir=".st_sync_cache"):
app()
Persistence uses DiskCache library, a mature pure-Python library. Any pickle-able data can be persisted.
In order to sync data, you need to enter a room. The easiest way of doing it is to use the same room for every session.
import streamlit as st
import streamlit_sync
with streamlit_sync.sync("default_room"):
app()
An alternative is to select the room to enter directly from the UI using the streamlit_sync.select_room_widget()
method. It will create a simple form on the sidebar in which you can choose an existing room from the list or create a new one. Once in a room, you can exit from it. Values of the room are still kept on the server but removed from the session.
import streamlit as st
import streamlit_sync
room_name = streamlit_sync.select_room_widget()
with streamlit_sync.sync(room_name):
app()
Note: the number of active sessions per room is indicative must not always exact. If a session closes, the server will notice it only when another session with trigger a sync in this room.
Instead of using the default UI with select_room_widget
, you can build your own using streamlit_sync.rooms.enter_room(room_name)
and streamlit_sync.rooms.exit_room()
.
By default, all widgets and values are synced. It is possible to restrain some widget as "private" by defining its own not-synced key:
x = st.slider("Select a value", key=streamlit_sync.get_not_synced_key("key"))
The same is also possible for state values:
synced_key = "my_custom_key"
username = streamlit_sync.get_not_synced_key("username")
st.session_state[synced_key] = 42 # All sessions will be synced with this value
st.session_state[username] = "Adrien Treuille" # Each session can store its own username
Some widgets are processed a bit differently by streamlit-sync, in particular buttons and form.
To avoid duplicate actions, buttons are never synced with the room. In order to sync a button, you will need to set a state value.
In this example, balloons with be send only on the session that clicked the button.
# Action is not shared !
if st.button(label="Send balloons"):
st.balloons()
Here is an example that syncs the result of the action.
# Nb of clicks is synced, not the action. !
if st.session_state.get("NB_CLICKS") is None:
st.session_state["NB_CLICKS"] = 0
if st.button(label="click"):
st.session_state["NB_CLICKS"] += 1
st.write("Clicked **" + str(st.session_state["NB_CLICKS"]) + "** times !")
Form data is synced only when the submit button is clicked, which is the intended use of forms. Same as for the buttons, the "submit action" is not synced, only the data.
Note: there is currently a bug in how the forms are synced. The fields are cleared only in the session that submitted the data.
- Test the library and especially the UI. At the moment, the sync between 2 sessions is only manually tested.
- Make an option to sync/not sync values by default. At the moment, all values are synced by default except if explicitly mentioned as "not synced". If would be good to be able to optionally set all values as private except if explicitly synced.
- Have a read-write/read-only mechanism with which some "admin" sessions could interacts with the widgets and some "normal users" could just see the current dashboard.
- Any other ideas are welcome :)