Skip to content

Instantly share code, notes, and snippets.

@toolittlecakes
Created August 18, 2024 12:57
Show Gist options
  • Save toolittlecakes/8642d52f7737a2a03695afa89331f3ae to your computer and use it in GitHub Desktop.
Save toolittlecakes/8642d52f7737a2a03695afa89331f3ae to your computer and use it in GitHub Desktop.
st_local_storage
# `pip install streamlit_js`
# See "https://discuss.streamlit.io/t/saving-data-in-local-storage-via-streamlit/28785/20"
import json
import uuid
from typing import Any
import streamlit as st
from streamlit_js import st_js, st_js_blocking
class StLocalStorage:
"""An Dict-like wrapper around browser local storage.
Values are stored JSON encoded."""
def __init__(self, prefix: str = "") -> None:
self._keys = {}
self._prefix = prefix
def __getitem__(self, key: str) -> Any:
code = f"""
return JSON.parse(localStorage.getItem('{self._prefix + key}'));
"""
id = f"get_{key}"
if id not in self._keys:
self._keys[id] = str(uuid.uuid4())
result = st_js_blocking(code, key=self._keys[id])
return json.loads(result) if result else None
def __setitem__(self, key: str, value: Any) -> None:
print("set", key, value)
value = json.dumps(value, ensure_ascii=False)
code = (
f"localStorage.setItem('{self._prefix + key}', JSON.stringify('{value}'));"
)
st_js(code)
# getitem has to refresh the value
get_id = f"get_{key}"
if get_id in self._keys:
del self._keys[get_id]
def __delitem__(self, key: str) -> None:
code = f"localStorage.removeItem('{self._prefix + key}');"
st_js_blocking(code)
# getitem has to refresh the value
get_id = f"get_{key}"
if get_id in self._keys:
del self._keys[get_id]
def __contains__(self, key: str) -> bool:
val = self.__getitem__(key)
return bool(val)
ss = st.session_state
if __name__ == "__main__":
st.title("st_local_storage basic example")
"Any values you save will be available after leaving / refreshing the tab"
if "ls" not in ss:
ss.ls = StLocalStorage()
if "key" not in ss:
ss.key = ss.ls["key"]
ss._key = ss.key
st.text_input("Key", key="_key")
if ss._key != ss.key:
# Order matters here, the condition should remain the same until js code finishes
ss.ls["key"] = ss._key
ss.key = ss._key
# if the key is changed, the value should be refreshed
if "value" in ss:
del ss["value"]
if not ss.key:
st.stop()
# Same shit as before, but ss.key instead of "key"
if f"value" not in ss:
ss.value = ss.ls[ss.key]
ss._value = ss.value
st.text_input("Value", key="_value")
if ss._value != ss.value:
ss.ls[ss.key] = ss._value
ss.value = ss._value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment