Last active
November 27, 2024 09:08
-
-
Save sfc-gh-jcarroll/e73f3ac80dadb5d0f2136d9d949c35a9 to your computer and use it in GitHub Desktop.
Local storage access in Streamlit - st_local_storage
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # NOTE: This feature uses browser local storage! AKA it stores data on a viewer's | |
| # machine. This may have privacy and compliance implications for your app. Be sure | |
| # to take that into account with any usage. | |
| import json | |
| from typing import Any | |
| import uuid | |
| import streamlit as st | |
| # Requires `pip install streamlit-js` | |
| # https://github.com/toolittlecakes/streamlit_js | |
| from streamlit_js import st_js | |
| KEY_PREFIX = "st_localstorage_" | |
| class StLocalStorage: | |
| """An Dict-like wrapper around browser local storage. | |
| Values are stored JSON encoded.""" | |
| def __init__(self): | |
| # Keep track of a UUID for each key to enable reruns | |
| if "_ls_unique_keys" not in st.session_state: | |
| st.session_state["_ls_unique_keys"] = {} | |
| # Hide the JS iframes | |
| self._container = st.container() | |
| with self._container: | |
| st.html(""" | |
| <style> | |
| .element-container:has(iframe[height="0"]) { | |
| display: none; | |
| } | |
| </style> | |
| """) | |
| def __getitem__(self, key: str) -> Any: | |
| if key not in st.session_state["_ls_unique_keys"]: | |
| st.session_state["_ls_unique_keys"][key] = str(uuid.uuid4()) | |
| code = f""" | |
| // The UUID changes on save, which causes this to rerun and update | |
| console.debug('{st.session_state["_ls_unique_keys"][key]}'); | |
| return JSON.parse(localStorage.getItem('{KEY_PREFIX + key}')); | |
| """ | |
| with self._container: | |
| result = st_js(code, key=st.session_state["_ls_unique_keys"][key]) | |
| if result and result[0]: | |
| return json.loads(result[0]) | |
| return None | |
| def __setitem__(self, key: str, value: Any) -> None: | |
| value = json.dumps(value, ensure_ascii=False) | |
| st.session_state["_ls_unique_keys"][key] = str(uuid.uuid4()) | |
| code = f""" | |
| console.debug('setting {key} to local storage'); | |
| localStorage.setItem('{KEY_PREFIX + key}', JSON.stringify('{value}')); | |
| """ | |
| with self._container: | |
| return st_js(code, key=st.session_state["_ls_unique_keys"][key] + "_set") | |
| def __delitem__(self, key: str) -> None: | |
| st.session_state["_ls_unique_keys"][key] = str(uuid.uuid4()) | |
| code = f"localStorage.removeItem('{KEY_PREFIX + key}');" | |
| with self._container: | |
| return st_js(code, key=st.session_state["_ls_unique_keys"][key] + "_del") | |
| def __contains__(self, key: str) -> bool: | |
| return self.__getitem__(key) is not None | |
| st_local_storage = StLocalStorage() | |
| if __name__ == "__main__": | |
| st.title("st_local_storage basic example") | |
| "Any values you save will be available after leaving / refreshing the tab" | |
| key = st.text_input("Key") | |
| value = st.text_input("Value") | |
| if st.button("Save"): | |
| st_local_storage[key] = value | |
| if st.button("Delete"): | |
| del st_local_storage[key] | |
| if key: | |
| f"Current value of {key} is:" | |
| st.write(st_local_storage[key]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I added get and set methods