Summary
I get a ValueError
saying that my custom object is not found in the iterable that I pass into st.selectbox
; however, the UI renders as expected, is without issues, and is functional. There is some strange behavior happening in this indexing thing and I was hoping someone could tell me what’s going on behind the indexing and why this problem disappears if I add a key=
argument in st.selectbox
.
Steps to reproduce
Code snippet:
from dataclasses import dataclass
import streamlit as st
@dataclass
class Foo:
name: str
value: float
# Assume no duplicates.
things = (Foo('a', 0.2), Foo('b', 0.3), Foo('c', 0.1))
thing = st.selectbox('Select one', things)
st.header(f'Selected: {thing}')
- Run streamlit
streamlit strangebox.py
- Open browser.
- Change from option ‘a’ to whatever else, even back to ‘a’ itself.
Expected behavior:
The select option changes to the selected option without any error messages in the backend.
Actual behavior:
An error message appears:
Exception in thread ScriptRunner.scriptThread:
Traceback (most recent call last):
File "/Users/muhammad.azman/.pyenv/versions/3.10.4/lib/python3.10/threading.py", line 1009, in _bootstrap_inner
self.run()
File "/Users/muhammad.azman/.pyenv/versions/3.10.4/lib/python3.10/threading.py", line 946, in run
self._target(*self._args, **self._kwargs)
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 311, in _run_script_thread
widget_states = self._session_state.get_widget_states()
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/state/safe_session_state.py", line 83, in get_widget_states
return self._state.get_widget_states()
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/state/session_state.py", line 550, in get_widget_states
return self._new_widget_state.as_widget_states()
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/state/session_state.py", line 223, in as_widget_states
states = [
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/state/session_state.py", line 226, in <listcomp>
if self.get_serialized(widget_id)
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/runtime/state/session_state.py", line 208, in get_serialized
serialized = metadata.serializer(item.value)
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/elements/selectbox.py", line 58, in serialize
return index_(self.options, v)
File "/Users/muhammad.azman/Projects/spo-ingestors/.venv/lib/python3.10/site-packages/streamlit/util.py", line 142, in index_
raise ValueError("{} is not in iterable".format(str(x)))
ValueError: Foo(name='c', value=0.1) is not in iterable
Debug info
- Streamlit version: Streamlit, version 1.19.0
- Python version: Python 3.10.4
- Using Conda? PipEnv? PyEnv? Pex? pyenv 2.3.1
- OS version: macOS Monterey v12.6
- Browser version: Google Chrome v110.0.5481.177 (Official Build) (x86_64)
Requirements file
Using Conda? PipEnv? PyEnv? Pex?
pyenv 2.3.1, under virtual environment
requirements:
streamlit
Links
N/A
Additional information
Did a little digging and placing print statements. Here’s what I found:
Events as they occured:
- Open browser:
in streamlit.runtime.state.session_state.get_serialized()
field='int_value'
item.value=Foo(name='a', value=0.2)
in streamlist.util.index_()
i=0 value=Foo(name='a', value=0.2)(4862353488) x=Foo(name='a', value=0.2)(4862358528): Match!
in streamlit.runtime.state.session_state.get_serialized()
field='int_value'
item.value=Foo(name='a', value=0.2)
in streamlist.util.index_()
i=0 value=Foo(name='a', value=0.2)(4862353488) x=Foo(name='a', value=0.2)(4862358528): Match!
- Change to option ‘b’
in streamlit.runtime.state.session_state.get_serialized()
field='int_value'
item.value=Foo(name='b', value=0.3)
in streamlist.util.index_()
i=0 value=Foo(name='a', value=0.2)(4862356848) x=Foo(name='b', value=0.3)(4862353680): Different.
i=1 value=Foo(name='b', value=0.3)(4862356704) x=Foo(name='b', value=0.3)(4862353680): Different.
i=2 value=Foo(name='c', value=0.1)(4914496944) x=Foo(name='b', value=0.3)(4862353680): Different.
DOH!
Exception in thread ScriptRunner.scriptThread:
... (see stack trace above)
Number in the parens in the logs are the object id you get using the id()
python built-in. No idea why it works like this.
Implementing an __eq__
dunder for my class did the trick but there’s nothing in the docs that would hint to if I would need to implement it for custom objects.