-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
st.selectbox could be typed so that it always returns T unless the index is None (etc) #8717
Comments
It seems like st.session_state.name = "Max"
st.selectbox("Your name", ["Sam", "Max"], key="name") isn't even documented on the session state page, only st.text_input("Your name", key="name")
# This exists now:
st.session_state.name Perhaps it would be worth it (to me) to give up pre-widget key-setting, if that could lead to facilitating better static typing guarantees. In that case it would be nice for selectbox to have an value parameter so I don't have to write in tons of value→index mapping logic into the index parameters I would have to be using. After reading #1532 I'm fairly certain I could get the result I want using value parameters. |
I would add onto this that it seems like the latest versions of integer: int = st.number_input("Number of things:", min_value=0, max_value=10) because typecheckers complain that |
Here's my workaround, for the time being: def typesafe_selectbox(label: str, options: Sequence[T], default: T|None = None, **kwargs: Any) -> T:
"""Call `st.selectbox` but don't pollute your type with `None` in the process;
if the selectbox would return `None`, return the value passed in as `default`.
If `default` is `None` (eg: not passed in), the value of `options[0]` is used.
The value of `default` (unless `None`) must be in `options`, on pain of runtime error;
and, furthermore, `options` must not be empty.
`options` is also a `Sequence` type rather than the broader `Iterable`
to ensure it isn't an exhaustible iterator that would be harmed by a call to `.index()`
`default` is named in analogy to a parameter in `st.multiselect`.
But there are other widgets, like `st.text_input`, that have an analogous parameter named `value` 🤷.
All arguments, including kwargs, are passed on to st.selectbox, either directly or indirectly.
It's not clear to me if there's a better & concise way to do the type signature of kwargs here.
Note that if you use st.session_state to set the value of the key of the selectbox, that takes priority over the `default` argument.
However, if you set the value of said key to `None`, this function will still return `options[0]`."""
i = 0 if default is None else options.index(default)
x = st.selectbox(label, options, index=i, **kwargs)
return x if x is not None else options[i] Here's some example usage code: st.write(typesafe_selectbox("test box empty str", ['', 'foo']))
st.write(typesafe_selectbox("test box empty str", ['']))
#st.write(typesafe_selectbox("test box empty list", [])) #this is an error
st.write(typesafe_selectbox("test box", ['a']))
st.write(typesafe_selectbox("test box2", ['a'], default='a'))
st.write(typesafe_selectbox("test box3", ['a', 'b'], default='b'))
st.write(typesafe_selectbox("test box4", ['a', 'b'], default='a'))
#unfortunately, this still displays as empty, even though it returns the first value:
st.session_state.tampered_key = None
st.write(typesafe_selectbox("test box5", ['a', 'b'], key="tampered_key"))
# This displays as, and returns, 'b'
st.session_state.tampered_key2 = 'b'
st.write(typesafe_selectbox("test box6", ['a', 'b'], key="tampered_key2", default='a'))
# st.session_state.tampered_key3 = 1 #this would be an error
# st.write(typesafe_selectbox("test box5", ['a', 'b'], key="tampered_key3")) |
Checklist
Summary
Currently, the return type of selectbox is
T | None
. As far as I know, the only way for selectbox to returnNone
is ifindex
isNone
or ifOptionSequence[T]
is empty (OptionSequence[]
?). These conditions could be added to the type signature of selectbox using overloads, and then in my program I wouldn't have toassert
orstr
the results of every st.selectbox. There would be one or two overloads that returnedNone | T
and one that returned justT
. NoReturn could also possibly be added to the return type union, because if you choose an invalid index the function will error and never return.Or maybe this goal is doomed. My project uses a lot of https://docs.streamlit.io/develop/api-reference/caching-and-state/st.session_state#session-state-and-widget-state-association stuff like:
and I don't really know how to account for this in static typing, because the program could set the session_state value of the widget to
None
.Furthermore, it may be unavoidable that there's always the possibility of an error in rendering, or suchlike, that would cause the widget to return None. I don't know enough to say.
So, I think this typing feature is desirable, but it may be impossible.
Why?
Currently, whenever I use a selectbox in my typed project, I have to deal with the type union somehow each time, even though the result should always be of a certain type, which is a bit annoying.
How?
No response
Additional Context
No response
The text was updated successfully, but these errors were encountered: