Skip to content

Instantly share code, notes, and snippets.

@treuille
Last active August 25, 2023 14:38
Show Gist options
  • Save treuille/bc4eacbb00bfc846b73eec2984869645 to your computer and use it in GitHub Desktop.
Save treuille/bc4eacbb00bfc846b73eec2984869645 to your computer and use it in GitHub Desktop.
Hack to implement a confirm_button in Streamlit v0.35
"""
THIS HAS BEEN DEPRECATED!
We propose you use st.form() instead:
https://blog.streamlit.io/introducing-submit-button-and-forms/
"""
import streamlit as st
import collections
import functools
import inspect
import textwrap
def cache_on_button_press(label, **cache_kwargs):
"""Function decorator to memoize function executions.
Parameters
----------
label : str
The label for the button to display prior to running the cached funnction.
cache_kwargs : Dict[Any, Any]
Additional parameters (such as show_spinner) to pass into the underlying @st.cache decorator.
Example
-------
This show how you could write a username/password tester:
>>> @cache_on_button_press('Authenticate')
... def authenticate(username, password):
... return username == "buddha" and password == "s4msara"
...
... username = st.text_input('username')
... password = st.text_input('password')
...
... if authenticate(username, password):
... st.success('Logged in.')
... else:
... st.error('Incorrect username or password')
"""
internal_cache_kwargs = dict(cache_kwargs)
internal_cache_kwargs['allow_output_mutation'] = True
internal_cache_kwargs['show_spinner'] = False
def function_decorator(func):
@functools.wraps(func)
def wrapped_func(*args, **kwargs):
@st.cache(**internal_cache_kwargs)
def get_cache_entry(func, args, kwargs):
class ButtonCacheEntry:
def __init__(self):
self.evaluated = False
self.return_value = None
def evaluate(self):
self.evaluated = True
self.return_value = func(*args, **kwargs)
return ButtonCacheEntry()
cache_entry = get_cache_entry(func, args, kwargs)
if not cache_entry.evaluated:
if st.button(label):
cache_entry.evaluate()
else:
raise st.ScriptRunner.StopException
return cache_entry.return_value
return wrapped_func
return function_decorator
def confirm_button_example():
@cache_on_button_press('Authenticate')
def authenticate(username, password):
return username == "buddha" and password == "s4msara"
username = st.text_input('username')
password = st.text_input('password')
if authenticate(username, password):
st.success('You are authenticated!')
st.write(st.slider('Test widget'))
else:
st.error('The username or password you have entered is invalid.')
def display_func_source(func):
code = inspect.getsource(confirm_button_example)
code = '\n'.join(code.splitlines()[1:]) # remove first line
st.code(textwrap.dedent(code))
if __name__ == '__main__':
st.write("""
This example shows a hack to create a "confirm button" in Streamlit, e.g.
to authenticate a username / password pair.
The correct answer is `buddha` / `s4msara`.
""")
display_func_source(confirm_button_example)
confirm_button_example()
@treuille
Copy link
Author

Right now this is not possible without using session_state which is experimental.

(Also, if you are using Streamlit for Teams, we are coming out with a viewer auth feature which will be vastly more elegant than this. @astrojams1 has more details on when this is coming out.)

@Nicholas-Autio-Mitchell
Copy link

Thanks for this - wondering why it is not included in streamlit itself?

@treuille
Copy link
Author

@nicholas-mitchell:

If you're talking about the confirm button specifically, this has been superseded by st.form which we just released.

If you're talking about session state more generally, it's coming in the next few months! We're working hard on it! 🎈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment