Skip to content

Instantly share code, notes, and snippets.

@treuille
Last active August 25, 2023 14:38
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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

To see this gist in action, please run:

https://gist.githubusercontent.com/treuille/bc4eacbb00bfc846b73eec2984869645/raw/059fd9e0fe6687daaf55683427ddc5c600fa3b22/confirm_button_hack.py

@treuille
Copy link
Author

As mentioned here, the general usage pattern is:

arg_1 = st.some_widget(...)
arg_2 = st.some_widget(...)
...

@cache_on_button_press('Submit')
def some_long_computation(arg_1, arg_2, ...)
   ... # <- some long computation

return_value = some_long_computation(arg_1, arg_2, ...)
# do something with the return value

@jacoblukose
Copy link

jacoblukose commented Oct 26, 2020

@treuille
module 'streamlit' has no attribute 'ScriptRunner'

Could you help in updating this gist to support 0.69.2 :)

@treuille
Copy link
Author

treuille commented Oct 26, 2020 via email

@Imane0
Copy link

Imane0 commented Apr 20, 2021

Thank you for dropping this. Do you have an idea of how to hide the password text input once the user is authenticated ?

@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